1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * AMD Pink Sardine ACP PCI Driver |
4 | * |
5 | * Copyright 2022 Advanced Micro Devices, Inc. |
6 | */ |
7 | |
8 | #include <linux/pci.h> |
9 | #include <linux/bitops.h> |
10 | #include <linux/module.h> |
11 | #include <linux/io.h> |
12 | #include <linux/delay.h> |
13 | #include <linux/platform_device.h> |
14 | #include <linux/acpi.h> |
15 | #include <linux/interrupt.h> |
16 | #include <sound/pcm_params.h> |
17 | #include <linux/pm_runtime.h> |
18 | #include <linux/iopoll.h> |
19 | #include <linux/soundwire/sdw_amd.h> |
20 | #include "../mach-config.h" |
21 | |
22 | #include "acp63.h" |
23 | |
24 | static int acp63_power_on(void __iomem *acp_base) |
25 | { |
26 | u32 val; |
27 | |
28 | val = readl(addr: acp_base + ACP_PGFSM_STATUS); |
29 | |
30 | if (!val) |
31 | return val; |
32 | |
33 | if ((val & ACP_PGFSM_STATUS_MASK) != ACP_POWER_ON_IN_PROGRESS) |
34 | writel(ACP_PGFSM_CNTL_POWER_ON_MASK, addr: acp_base + ACP_PGFSM_CONTROL); |
35 | |
36 | return readl_poll_timeout(acp_base + ACP_PGFSM_STATUS, val, !val, DELAY_US, ACP_TIMEOUT); |
37 | } |
38 | |
39 | static int acp63_reset(void __iomem *acp_base) |
40 | { |
41 | u32 val; |
42 | int ret; |
43 | |
44 | writel(val: 1, addr: acp_base + ACP_SOFT_RESET); |
45 | |
46 | ret = readl_poll_timeout(acp_base + ACP_SOFT_RESET, val, |
47 | val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK, |
48 | DELAY_US, ACP_TIMEOUT); |
49 | if (ret) |
50 | return ret; |
51 | |
52 | writel(val: 0, addr: acp_base + ACP_SOFT_RESET); |
53 | |
54 | return readl_poll_timeout(acp_base + ACP_SOFT_RESET, val, !val, DELAY_US, ACP_TIMEOUT); |
55 | } |
56 | |
57 | static void acp63_enable_interrupts(void __iomem *acp_base) |
58 | { |
59 | writel(val: 1, addr: acp_base + ACP_EXTERNAL_INTR_ENB); |
60 | writel(ACP_ERROR_IRQ, addr: acp_base + ACP_EXTERNAL_INTR_CNTL); |
61 | } |
62 | |
63 | static void acp63_disable_interrupts(void __iomem *acp_base) |
64 | { |
65 | writel(ACP_EXT_INTR_STAT_CLEAR_MASK, addr: acp_base + ACP_EXTERNAL_INTR_STAT); |
66 | writel(val: 0, addr: acp_base + ACP_EXTERNAL_INTR_CNTL); |
67 | writel(val: 0, addr: acp_base + ACP_EXTERNAL_INTR_ENB); |
68 | } |
69 | |
70 | static int acp63_init(void __iomem *acp_base, struct device *dev) |
71 | { |
72 | int ret; |
73 | |
74 | ret = acp63_power_on(acp_base); |
75 | if (ret) { |
76 | dev_err(dev, "ACP power on failed\n" ); |
77 | return ret; |
78 | } |
79 | writel(val: 0x01, addr: acp_base + ACP_CONTROL); |
80 | ret = acp63_reset(acp_base); |
81 | if (ret) { |
82 | dev_err(dev, "ACP reset failed\n" ); |
83 | return ret; |
84 | } |
85 | acp63_enable_interrupts(acp_base); |
86 | return 0; |
87 | } |
88 | |
89 | static int acp63_deinit(void __iomem *acp_base, struct device *dev) |
90 | { |
91 | int ret; |
92 | |
93 | acp63_disable_interrupts(acp_base); |
94 | ret = acp63_reset(acp_base); |
95 | if (ret) { |
96 | dev_err(dev, "ACP reset failed\n" ); |
97 | return ret; |
98 | } |
99 | writel(val: 0, addr: acp_base + ACP_CONTROL); |
100 | return 0; |
101 | } |
102 | |
103 | static irqreturn_t acp63_irq_thread(int irq, void *context) |
104 | { |
105 | struct sdw_dma_dev_data *sdw_dma_data; |
106 | struct acp63_dev_data *adata = context; |
107 | u32 stream_index; |
108 | |
109 | sdw_dma_data = dev_get_drvdata(dev: &adata->sdw_dma_dev->dev); |
110 | |
111 | for (stream_index = 0; stream_index < ACP63_SDW0_DMA_MAX_STREAMS; stream_index++) { |
112 | if (adata->sdw0_dma_intr_stat[stream_index]) { |
113 | if (sdw_dma_data->sdw0_dma_stream[stream_index]) |
114 | snd_pcm_period_elapsed(substream: sdw_dma_data->sdw0_dma_stream[stream_index]); |
115 | adata->sdw0_dma_intr_stat[stream_index] = 0; |
116 | } |
117 | } |
118 | for (stream_index = 0; stream_index < ACP63_SDW1_DMA_MAX_STREAMS; stream_index++) { |
119 | if (adata->sdw1_dma_intr_stat[stream_index]) { |
120 | if (sdw_dma_data->sdw1_dma_stream[stream_index]) |
121 | snd_pcm_period_elapsed(substream: sdw_dma_data->sdw1_dma_stream[stream_index]); |
122 | adata->sdw1_dma_intr_stat[stream_index] = 0; |
123 | } |
124 | } |
125 | return IRQ_HANDLED; |
126 | } |
127 | |
128 | static irqreturn_t acp63_irq_handler(int irq, void *dev_id) |
129 | { |
130 | struct acp63_dev_data *adata; |
131 | struct pdm_dev_data *ps_pdm_data; |
132 | struct amd_sdw_manager *amd_manager; |
133 | u32 ext_intr_stat, ext_intr_stat1; |
134 | u32 stream_id = 0; |
135 | u16 irq_flag = 0; |
136 | u16 sdw_dma_irq_flag = 0; |
137 | u16 index; |
138 | |
139 | adata = dev_id; |
140 | if (!adata) |
141 | return IRQ_NONE; |
142 | /* ACP interrupts will be cleared by reading particular bit and writing |
143 | * same value to the status register. writing zero's doesn't have any |
144 | * effect. |
145 | * Bit by bit checking of IRQ field is implemented. |
146 | */ |
147 | ext_intr_stat = readl(addr: adata->acp63_base + ACP_EXTERNAL_INTR_STAT); |
148 | if (ext_intr_stat & ACP_SDW0_STAT) { |
149 | writel(ACP_SDW0_STAT, addr: adata->acp63_base + ACP_EXTERNAL_INTR_STAT); |
150 | amd_manager = dev_get_drvdata(dev: &adata->sdw->pdev[0]->dev); |
151 | if (amd_manager) |
152 | schedule_work(work: &amd_manager->amd_sdw_irq_thread); |
153 | irq_flag = 1; |
154 | } |
155 | |
156 | ext_intr_stat1 = readl(addr: adata->acp63_base + ACP_EXTERNAL_INTR_STAT1); |
157 | if (ext_intr_stat1 & ACP_SDW1_STAT) { |
158 | writel(ACP_SDW1_STAT, addr: adata->acp63_base + ACP_EXTERNAL_INTR_STAT1); |
159 | amd_manager = dev_get_drvdata(dev: &adata->sdw->pdev[1]->dev); |
160 | if (amd_manager) |
161 | schedule_work(work: &amd_manager->amd_sdw_irq_thread); |
162 | irq_flag = 1; |
163 | } |
164 | |
165 | if (ext_intr_stat & ACP_ERROR_IRQ) { |
166 | writel(ACP_ERROR_IRQ, addr: adata->acp63_base + ACP_EXTERNAL_INTR_STAT); |
167 | /* TODO: Report SoundWire Manager instance errors */ |
168 | writel(val: 0, addr: adata->acp63_base + ACP_SW0_I2S_ERROR_REASON); |
169 | writel(val: 0, addr: adata->acp63_base + ACP_SW1_I2S_ERROR_REASON); |
170 | writel(val: 0, addr: adata->acp63_base + ACP_ERROR_STATUS); |
171 | irq_flag = 1; |
172 | } |
173 | |
174 | if (ext_intr_stat & BIT(PDM_DMA_STAT)) { |
175 | ps_pdm_data = dev_get_drvdata(dev: &adata->pdm_dev->dev); |
176 | writel(BIT(PDM_DMA_STAT), addr: adata->acp63_base + ACP_EXTERNAL_INTR_STAT); |
177 | if (ps_pdm_data->capture_stream) |
178 | snd_pcm_period_elapsed(substream: ps_pdm_data->capture_stream); |
179 | irq_flag = 1; |
180 | } |
181 | if (ext_intr_stat & ACP_SDW_DMA_IRQ_MASK) { |
182 | for (index = ACP_AUDIO2_RX_THRESHOLD; index <= ACP_AUDIO0_TX_THRESHOLD; index++) { |
183 | if (ext_intr_stat & BIT(index)) { |
184 | writel(BIT(index), addr: adata->acp63_base + ACP_EXTERNAL_INTR_STAT); |
185 | switch (index) { |
186 | case ACP_AUDIO0_TX_THRESHOLD: |
187 | stream_id = ACP_SDW0_AUDIO0_TX; |
188 | break; |
189 | case ACP_AUDIO1_TX_THRESHOLD: |
190 | stream_id = ACP_SDW0_AUDIO1_TX; |
191 | break; |
192 | case ACP_AUDIO2_TX_THRESHOLD: |
193 | stream_id = ACP_SDW0_AUDIO2_TX; |
194 | break; |
195 | case ACP_AUDIO0_RX_THRESHOLD: |
196 | stream_id = ACP_SDW0_AUDIO0_RX; |
197 | break; |
198 | case ACP_AUDIO1_RX_THRESHOLD: |
199 | stream_id = ACP_SDW0_AUDIO1_RX; |
200 | break; |
201 | case ACP_AUDIO2_RX_THRESHOLD: |
202 | stream_id = ACP_SDW0_AUDIO2_RX; |
203 | break; |
204 | } |
205 | |
206 | adata->sdw0_dma_intr_stat[stream_id] = 1; |
207 | sdw_dma_irq_flag = 1; |
208 | } |
209 | } |
210 | } |
211 | |
212 | if (ext_intr_stat1 & ACP_P1_AUDIO1_RX_THRESHOLD) { |
213 | writel(ACP_P1_AUDIO1_RX_THRESHOLD, |
214 | addr: adata->acp63_base + ACP_EXTERNAL_INTR_STAT1); |
215 | adata->sdw1_dma_intr_stat[ACP_SDW1_AUDIO1_RX] = 1; |
216 | sdw_dma_irq_flag = 1; |
217 | } |
218 | |
219 | if (ext_intr_stat1 & ACP_P1_AUDIO1_TX_THRESHOLD) { |
220 | writel(ACP_P1_AUDIO1_TX_THRESHOLD, |
221 | addr: adata->acp63_base + ACP_EXTERNAL_INTR_STAT1); |
222 | adata->sdw1_dma_intr_stat[ACP_SDW1_AUDIO1_TX] = 1; |
223 | sdw_dma_irq_flag = 1; |
224 | } |
225 | |
226 | if (sdw_dma_irq_flag) |
227 | return IRQ_WAKE_THREAD; |
228 | |
229 | if (irq_flag) |
230 | return IRQ_HANDLED; |
231 | else |
232 | return IRQ_NONE; |
233 | } |
234 | |
235 | #if IS_ENABLED(CONFIG_SND_SOC_AMD_SOUNDWIRE) |
236 | static int acp_scan_sdw_devices(struct device *dev, u64 addr) |
237 | { |
238 | struct acpi_device *sdw_dev; |
239 | struct acp63_dev_data *acp_data; |
240 | |
241 | acp_data = dev_get_drvdata(dev); |
242 | if (!addr) |
243 | return -ENODEV; |
244 | |
245 | sdw_dev = acpi_find_child_device(ACPI_COMPANION(dev), address: addr, check_children: 0); |
246 | if (!sdw_dev) |
247 | return -ENODEV; |
248 | |
249 | acp_data->info.handle = sdw_dev->handle; |
250 | acp_data->info.count = AMD_SDW_MAX_MANAGERS; |
251 | return amd_sdw_scan_controller(info: &acp_data->info); |
252 | } |
253 | |
254 | static int amd_sdw_probe(struct device *dev) |
255 | { |
256 | struct acp63_dev_data *acp_data; |
257 | struct sdw_amd_res sdw_res; |
258 | int ret; |
259 | |
260 | acp_data = dev_get_drvdata(dev); |
261 | memset(&sdw_res, 0, sizeof(sdw_res)); |
262 | sdw_res.addr = acp_data->addr; |
263 | sdw_res.reg_range = acp_data->reg_range; |
264 | sdw_res.handle = acp_data->info.handle; |
265 | sdw_res.parent = dev; |
266 | sdw_res.dev = dev; |
267 | sdw_res.acp_lock = &acp_data->acp_lock; |
268 | sdw_res.count = acp_data->info.count; |
269 | sdw_res.mmio_base = acp_data->acp63_base; |
270 | sdw_res.link_mask = acp_data->info.link_mask; |
271 | ret = sdw_amd_probe(res: &sdw_res, ctx: &acp_data->sdw); |
272 | if (ret) |
273 | dev_err(dev, "error: SoundWire probe failed\n" ); |
274 | return ret; |
275 | } |
276 | |
277 | static int amd_sdw_exit(struct acp63_dev_data *acp_data) |
278 | { |
279 | if (acp_data->sdw) |
280 | sdw_amd_exit(ctx: acp_data->sdw); |
281 | acp_data->sdw = NULL; |
282 | |
283 | return 0; |
284 | } |
285 | |
286 | static struct snd_soc_acpi_mach *acp63_sdw_machine_select(struct device *dev) |
287 | { |
288 | struct snd_soc_acpi_mach *mach; |
289 | const struct snd_soc_acpi_link_adr *link; |
290 | struct acp63_dev_data *acp_data = dev_get_drvdata(dev); |
291 | int ret, i; |
292 | |
293 | if (acp_data->info.count) { |
294 | ret = sdw_amd_get_slave_info(ctx: acp_data->sdw); |
295 | if (ret) { |
296 | dev_dbg(dev, "failed to read slave information\n" ); |
297 | return NULL; |
298 | } |
299 | for (mach = acp_data->machines; mach; mach++) { |
300 | if (!mach->links) |
301 | break; |
302 | link = mach->links; |
303 | for (i = 0; i < acp_data->info.count && link->num_adr; link++, i++) { |
304 | if (!snd_soc_acpi_sdw_link_slaves_found(dev, link, |
305 | ids: acp_data->sdw->ids, |
306 | num_slaves: acp_data->sdw->num_slaves)) |
307 | break; |
308 | } |
309 | if (i == acp_data->info.count || !link->num_adr) |
310 | break; |
311 | } |
312 | if (mach && mach->link_mask) { |
313 | mach->mach_params.links = mach->links; |
314 | mach->mach_params.link_mask = mach->link_mask; |
315 | return mach; |
316 | } |
317 | } |
318 | dev_dbg(dev, "No SoundWire machine driver found\n" ); |
319 | return NULL; |
320 | } |
321 | #else |
322 | static int acp_scan_sdw_devices(struct device *dev, u64 addr) |
323 | { |
324 | return 0; |
325 | } |
326 | |
327 | static int amd_sdw_probe(struct device *dev) |
328 | { |
329 | return 0; |
330 | } |
331 | |
332 | static int amd_sdw_exit(struct acp63_dev_data *acp_data) |
333 | { |
334 | return 0; |
335 | } |
336 | |
337 | static struct snd_soc_acpi_mach *acp63_sdw_machine_select(struct device *dev) |
338 | { |
339 | return NULL; |
340 | } |
341 | #endif |
342 | |
343 | static int acp63_machine_register(struct device *dev) |
344 | { |
345 | struct snd_soc_acpi_mach *mach; |
346 | struct acp63_dev_data *adata = dev_get_drvdata(dev); |
347 | int size; |
348 | |
349 | if (adata->is_sdw_dev && adata->is_sdw_config) { |
350 | size = sizeof(*adata->machines); |
351 | mach = acp63_sdw_machine_select(dev); |
352 | if (mach) { |
353 | adata->mach_dev = platform_device_register_data(parent: dev, name: mach->drv_name, |
354 | PLATFORM_DEVID_NONE, data: mach, |
355 | size); |
356 | if (IS_ERR(ptr: adata->mach_dev)) { |
357 | dev_err(dev, |
358 | "cannot register Machine device for SoundWire Interface\n" ); |
359 | return PTR_ERR(ptr: adata->mach_dev); |
360 | } |
361 | } |
362 | |
363 | } else if (adata->is_pdm_dev && !adata->is_sdw_dev && adata->is_pdm_config) { |
364 | adata->mach_dev = platform_device_register_data(parent: dev, name: "acp_ps_mach" , |
365 | PLATFORM_DEVID_NONE, NULL, size: 0); |
366 | if (IS_ERR(ptr: adata->mach_dev)) { |
367 | dev_err(dev, "cannot register amd_ps_mach device\n" ); |
368 | return PTR_ERR(ptr: adata->mach_dev); |
369 | } |
370 | } |
371 | return 0; |
372 | } |
373 | |
374 | static int get_acp63_device_config(struct pci_dev *pci, struct acp63_dev_data *acp_data) |
375 | { |
376 | struct acpi_device *pdm_dev; |
377 | const union acpi_object *obj; |
378 | u32 config; |
379 | bool is_dmic_dev = false; |
380 | bool is_sdw_dev = false; |
381 | int ret; |
382 | |
383 | config = readl(addr: acp_data->acp63_base + ACP_PIN_CONFIG); |
384 | switch (config) { |
385 | case ACP_CONFIG_4: |
386 | case ACP_CONFIG_5: |
387 | case ACP_CONFIG_10: |
388 | case ACP_CONFIG_11: |
389 | acp_data->is_pdm_config = true; |
390 | break; |
391 | case ACP_CONFIG_2: |
392 | case ACP_CONFIG_3: |
393 | acp_data->is_sdw_config = true; |
394 | break; |
395 | case ACP_CONFIG_6: |
396 | case ACP_CONFIG_7: |
397 | case ACP_CONFIG_12: |
398 | case ACP_CONFIG_8: |
399 | case ACP_CONFIG_13: |
400 | case ACP_CONFIG_14: |
401 | acp_data->is_pdm_config = true; |
402 | acp_data->is_sdw_config = true; |
403 | break; |
404 | default: |
405 | break; |
406 | } |
407 | |
408 | if (acp_data->is_pdm_config) { |
409 | pdm_dev = acpi_find_child_device(ACPI_COMPANION(&pci->dev), ACP63_DMIC_ADDR, check_children: 0); |
410 | if (pdm_dev) { |
411 | /* is_dmic_dev flag will be set when ACP PDM controller device exists */ |
412 | if (!acpi_dev_get_property(adev: pdm_dev, name: "acp-audio-device-type" , |
413 | ACPI_TYPE_INTEGER, obj: &obj) && |
414 | obj->integer.value == ACP_DMIC_DEV) |
415 | is_dmic_dev = true; |
416 | } |
417 | } |
418 | |
419 | if (acp_data->is_sdw_config) { |
420 | ret = acp_scan_sdw_devices(dev: &pci->dev, ACP63_SDW_ADDR); |
421 | if (!ret && acp_data->info.link_mask) |
422 | is_sdw_dev = true; |
423 | } |
424 | |
425 | acp_data->is_pdm_dev = is_dmic_dev; |
426 | acp_data->is_sdw_dev = is_sdw_dev; |
427 | if (!is_dmic_dev && !is_sdw_dev) { |
428 | dev_dbg(&pci->dev, "No PDM or SoundWire manager devices found\n" ); |
429 | return -ENODEV; |
430 | } |
431 | return 0; |
432 | } |
433 | |
434 | static void acp63_fill_platform_dev_info(struct platform_device_info *pdevinfo, |
435 | struct device *parent, |
436 | struct fwnode_handle *fw_node, |
437 | char *name, unsigned int id, |
438 | const struct resource *res, |
439 | unsigned int num_res, |
440 | const void *data, |
441 | size_t size_data) |
442 | { |
443 | pdevinfo->name = name; |
444 | pdevinfo->id = id; |
445 | pdevinfo->parent = parent; |
446 | pdevinfo->num_res = num_res; |
447 | pdevinfo->res = res; |
448 | pdevinfo->data = data; |
449 | pdevinfo->size_data = size_data; |
450 | pdevinfo->fwnode = fw_node; |
451 | } |
452 | |
453 | static int create_acp63_platform_devs(struct pci_dev *pci, struct acp63_dev_data *adata, u32 addr) |
454 | { |
455 | struct platform_device_info pdevinfo; |
456 | struct device *parent; |
457 | int ret; |
458 | |
459 | parent = &pci->dev; |
460 | |
461 | if (adata->is_sdw_dev || adata->is_pdm_dev) { |
462 | adata->res = devm_kzalloc(dev: &pci->dev, size: sizeof(struct resource), GFP_KERNEL); |
463 | if (!adata->res) { |
464 | ret = -ENOMEM; |
465 | goto de_init; |
466 | } |
467 | adata->res->flags = IORESOURCE_MEM; |
468 | adata->res->start = addr; |
469 | adata->res->end = addr + (ACP63_REG_END - ACP63_REG_START); |
470 | memset(&pdevinfo, 0, sizeof(pdevinfo)); |
471 | } |
472 | |
473 | if (adata->is_pdm_dev && adata->is_pdm_config) { |
474 | acp63_fill_platform_dev_info(pdevinfo: &pdevinfo, parent, NULL, name: "acp_ps_pdm_dma" , |
475 | id: 0, res: adata->res, num_res: 1, NULL, size_data: 0); |
476 | |
477 | adata->pdm_dev = platform_device_register_full(pdevinfo: &pdevinfo); |
478 | if (IS_ERR(ptr: adata->pdm_dev)) { |
479 | dev_err(&pci->dev, |
480 | "cannot register %s device\n" , pdevinfo.name); |
481 | ret = PTR_ERR(ptr: adata->pdm_dev); |
482 | goto de_init; |
483 | } |
484 | memset(&pdevinfo, 0, sizeof(pdevinfo)); |
485 | acp63_fill_platform_dev_info(pdevinfo: &pdevinfo, parent, NULL, name: "dmic-codec" , |
486 | id: 0, NULL, num_res: 0, NULL, size_data: 0); |
487 | adata->dmic_codec_dev = platform_device_register_full(pdevinfo: &pdevinfo); |
488 | if (IS_ERR(ptr: adata->dmic_codec_dev)) { |
489 | dev_err(&pci->dev, |
490 | "cannot register %s device\n" , pdevinfo.name); |
491 | ret = PTR_ERR(ptr: adata->dmic_codec_dev); |
492 | goto unregister_pdm_dev; |
493 | } |
494 | } |
495 | if (adata->is_sdw_dev && adata->is_sdw_config) { |
496 | ret = amd_sdw_probe(dev: &pci->dev); |
497 | if (ret) { |
498 | if (adata->is_pdm_dev) |
499 | goto unregister_dmic_codec_dev; |
500 | else |
501 | goto de_init; |
502 | } |
503 | memset(&pdevinfo, 0, sizeof(pdevinfo)); |
504 | acp63_fill_platform_dev_info(pdevinfo: &pdevinfo, parent, NULL, name: "amd_ps_sdw_dma" , |
505 | id: 0, res: adata->res, num_res: 1, NULL, size_data: 0); |
506 | |
507 | adata->sdw_dma_dev = platform_device_register_full(pdevinfo: &pdevinfo); |
508 | if (IS_ERR(ptr: adata->sdw_dma_dev)) { |
509 | dev_err(&pci->dev, |
510 | "cannot register %s device\n" , pdevinfo.name); |
511 | ret = PTR_ERR(ptr: adata->sdw_dma_dev); |
512 | if (adata->is_pdm_dev) |
513 | goto unregister_dmic_codec_dev; |
514 | else |
515 | goto de_init; |
516 | } |
517 | } |
518 | |
519 | return 0; |
520 | unregister_dmic_codec_dev: |
521 | platform_device_unregister(adata->dmic_codec_dev); |
522 | unregister_pdm_dev: |
523 | platform_device_unregister(adata->pdm_dev); |
524 | de_init: |
525 | if (acp63_deinit(acp_base: adata->acp63_base, dev: &pci->dev)) |
526 | dev_err(&pci->dev, "ACP de-init failed\n" ); |
527 | return ret; |
528 | } |
529 | |
530 | static int snd_acp63_probe(struct pci_dev *pci, |
531 | const struct pci_device_id *pci_id) |
532 | { |
533 | struct acp63_dev_data *adata; |
534 | u32 addr; |
535 | u32 irqflags, flag; |
536 | int ret; |
537 | |
538 | irqflags = IRQF_SHARED; |
539 | |
540 | /* Return if acp config flag is defined */ |
541 | flag = snd_amd_acp_find_config(pci); |
542 | if (flag) |
543 | return -ENODEV; |
544 | |
545 | /* Pink Sardine device check */ |
546 | switch (pci->revision) { |
547 | case 0x63: |
548 | break; |
549 | default: |
550 | dev_dbg(&pci->dev, "acp63 pci device not found\n" ); |
551 | return -ENODEV; |
552 | } |
553 | if (pci_enable_device(dev: pci)) { |
554 | dev_err(&pci->dev, "pci_enable_device failed\n" ); |
555 | return -ENODEV; |
556 | } |
557 | |
558 | ret = pci_request_regions(pci, "AMD ACP6.2 audio" ); |
559 | if (ret < 0) { |
560 | dev_err(&pci->dev, "pci_request_regions failed\n" ); |
561 | goto disable_pci; |
562 | } |
563 | adata = devm_kzalloc(dev: &pci->dev, size: sizeof(struct acp63_dev_data), |
564 | GFP_KERNEL); |
565 | if (!adata) { |
566 | ret = -ENOMEM; |
567 | goto release_regions; |
568 | } |
569 | |
570 | addr = pci_resource_start(pci, 0); |
571 | adata->acp63_base = devm_ioremap(dev: &pci->dev, offset: addr, |
572 | pci_resource_len(pci, 0)); |
573 | if (!adata->acp63_base) { |
574 | ret = -ENOMEM; |
575 | goto release_regions; |
576 | } |
577 | adata->addr = addr; |
578 | adata->reg_range = ACP63_REG_END - ACP63_REG_START; |
579 | pci_set_master(dev: pci); |
580 | pci_set_drvdata(pdev: pci, data: adata); |
581 | mutex_init(&adata->acp_lock); |
582 | ret = acp63_init(acp_base: adata->acp63_base, dev: &pci->dev); |
583 | if (ret) |
584 | goto release_regions; |
585 | ret = devm_request_threaded_irq(dev: &pci->dev, irq: pci->irq, handler: acp63_irq_handler, |
586 | thread_fn: acp63_irq_thread, irqflags, devname: "ACP_PCI_IRQ" , dev_id: adata); |
587 | if (ret) { |
588 | dev_err(&pci->dev, "ACP PCI IRQ request failed\n" ); |
589 | goto de_init; |
590 | } |
591 | ret = get_acp63_device_config(pci, acp_data: adata); |
592 | /* ACP PCI driver probe should be continued even PDM or SoundWire Devices are not found */ |
593 | if (ret) { |
594 | dev_dbg(&pci->dev, "get acp device config failed:%d\n" , ret); |
595 | goto skip_pdev_creation; |
596 | } |
597 | ret = create_acp63_platform_devs(pci, adata, addr); |
598 | if (ret < 0) { |
599 | dev_err(&pci->dev, "ACP platform devices creation failed\n" ); |
600 | goto de_init; |
601 | } |
602 | ret = acp63_machine_register(dev: &pci->dev); |
603 | if (ret) { |
604 | dev_err(&pci->dev, "ACP machine register failed\n" ); |
605 | goto de_init; |
606 | } |
607 | skip_pdev_creation: |
608 | device_set_wakeup_enable(dev: &pci->dev, enable: true); |
609 | pm_runtime_set_autosuspend_delay(dev: &pci->dev, ACP_SUSPEND_DELAY_MS); |
610 | pm_runtime_use_autosuspend(dev: &pci->dev); |
611 | pm_runtime_put_noidle(dev: &pci->dev); |
612 | pm_runtime_allow(dev: &pci->dev); |
613 | return 0; |
614 | de_init: |
615 | if (acp63_deinit(acp_base: adata->acp63_base, dev: &pci->dev)) |
616 | dev_err(&pci->dev, "ACP de-init failed\n" ); |
617 | release_regions: |
618 | pci_release_regions(pci); |
619 | disable_pci: |
620 | pci_disable_device(dev: pci); |
621 | |
622 | return ret; |
623 | } |
624 | |
625 | static bool check_acp_sdw_enable_status(struct acp63_dev_data *adata) |
626 | { |
627 | u32 sdw0_en, sdw1_en; |
628 | |
629 | sdw0_en = readl(addr: adata->acp63_base + ACP_SW0_EN); |
630 | sdw1_en = readl(addr: adata->acp63_base + ACP_SW1_EN); |
631 | return (sdw0_en || sdw1_en); |
632 | } |
633 | |
634 | static void handle_acp63_sdw_pme_event(struct acp63_dev_data *adata) |
635 | { |
636 | u32 val; |
637 | |
638 | val = readl(addr: adata->acp63_base + ACP_SW0_WAKE_EN); |
639 | if (val && adata->sdw->pdev[0]) |
640 | pm_request_resume(dev: &adata->sdw->pdev[0]->dev); |
641 | |
642 | val = readl(addr: adata->acp63_base + ACP_SW1_WAKE_EN); |
643 | if (val && adata->sdw->pdev[1]) |
644 | pm_request_resume(dev: &adata->sdw->pdev[1]->dev); |
645 | } |
646 | |
647 | static int __maybe_unused snd_acp63_suspend(struct device *dev) |
648 | { |
649 | struct acp63_dev_data *adata; |
650 | int ret; |
651 | |
652 | adata = dev_get_drvdata(dev); |
653 | if (adata->is_sdw_dev) { |
654 | adata->sdw_en_stat = check_acp_sdw_enable_status(adata); |
655 | if (adata->sdw_en_stat) |
656 | return 0; |
657 | } |
658 | ret = acp63_deinit(acp_base: adata->acp63_base, dev); |
659 | if (ret) |
660 | dev_err(dev, "ACP de-init failed\n" ); |
661 | |
662 | return ret; |
663 | } |
664 | |
665 | static int __maybe_unused snd_acp63_runtime_resume(struct device *dev) |
666 | { |
667 | struct acp63_dev_data *adata; |
668 | int ret; |
669 | |
670 | adata = dev_get_drvdata(dev); |
671 | if (adata->sdw_en_stat) |
672 | return 0; |
673 | |
674 | ret = acp63_init(acp_base: adata->acp63_base, dev); |
675 | if (ret) { |
676 | dev_err(dev, "ACP init failed\n" ); |
677 | return ret; |
678 | } |
679 | |
680 | if (!adata->sdw_en_stat) |
681 | handle_acp63_sdw_pme_event(adata); |
682 | return 0; |
683 | } |
684 | |
685 | static int __maybe_unused snd_acp63_resume(struct device *dev) |
686 | { |
687 | struct acp63_dev_data *adata; |
688 | int ret; |
689 | |
690 | adata = dev_get_drvdata(dev); |
691 | if (adata->sdw_en_stat) |
692 | return 0; |
693 | |
694 | ret = acp63_init(acp_base: adata->acp63_base, dev); |
695 | if (ret) |
696 | dev_err(dev, "ACP init failed\n" ); |
697 | |
698 | return ret; |
699 | } |
700 | |
701 | static const struct dev_pm_ops acp63_pm_ops = { |
702 | SET_RUNTIME_PM_OPS(snd_acp63_suspend, snd_acp63_runtime_resume, NULL) |
703 | SET_SYSTEM_SLEEP_PM_OPS(snd_acp63_suspend, snd_acp63_resume) |
704 | }; |
705 | |
706 | static void snd_acp63_remove(struct pci_dev *pci) |
707 | { |
708 | struct acp63_dev_data *adata; |
709 | int ret; |
710 | |
711 | adata = pci_get_drvdata(pdev: pci); |
712 | if (adata->sdw) { |
713 | amd_sdw_exit(acp_data: adata); |
714 | platform_device_unregister(adata->sdw_dma_dev); |
715 | } |
716 | if (adata->is_pdm_dev) { |
717 | platform_device_unregister(adata->pdm_dev); |
718 | platform_device_unregister(adata->dmic_codec_dev); |
719 | } |
720 | if (adata->mach_dev) |
721 | platform_device_unregister(adata->mach_dev); |
722 | ret = acp63_deinit(acp_base: adata->acp63_base, dev: &pci->dev); |
723 | if (ret) |
724 | dev_err(&pci->dev, "ACP de-init failed\n" ); |
725 | pm_runtime_forbid(dev: &pci->dev); |
726 | pm_runtime_get_noresume(dev: &pci->dev); |
727 | pci_release_regions(pci); |
728 | pci_disable_device(dev: pci); |
729 | } |
730 | |
731 | static const struct pci_device_id snd_acp63_ids[] = { |
732 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_DEVICE_ID), |
733 | .class = PCI_CLASS_MULTIMEDIA_OTHER << 8, |
734 | .class_mask = 0xffffff }, |
735 | { 0, }, |
736 | }; |
737 | MODULE_DEVICE_TABLE(pci, snd_acp63_ids); |
738 | |
739 | static struct pci_driver ps_acp63_driver = { |
740 | .name = KBUILD_MODNAME, |
741 | .id_table = snd_acp63_ids, |
742 | .probe = snd_acp63_probe, |
743 | .remove = snd_acp63_remove, |
744 | .driver = { |
745 | .pm = &acp63_pm_ops, |
746 | } |
747 | }; |
748 | |
749 | module_pci_driver(ps_acp63_driver); |
750 | |
751 | MODULE_AUTHOR("Vijendar.Mukunda@amd.com" ); |
752 | MODULE_AUTHOR("Syed.SabaKareem@amd.com" ); |
753 | MODULE_DESCRIPTION("AMD ACP Pink Sardine PCI driver" ); |
754 | MODULE_IMPORT_NS(SOUNDWIRE_AMD_INIT); |
755 | MODULE_IMPORT_NS(SND_AMD_SOUNDWIRE_ACPI); |
756 | MODULE_LICENSE("GPL v2" ); |
757 | |