]>
Commit | Line | Data |
---|---|---|
747503b1 LG |
1 | // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) |
2 | // | |
3 | // This file is provided under a dual BSD/GPLv2 license. When using or | |
4 | // redistributing this file, you may do so under either license. | |
5 | // | |
6 | // Copyright(c) 2018 Intel Corporation. All rights reserved. | |
7 | // | |
8 | // Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com> | |
9 | // Ranjani Sridharan <ranjani.sridharan@linux.intel.com> | |
10 | // Rander Wang <rander.wang@intel.com> | |
11 | // Keyon Jie <yang.jie@linux.intel.com> | |
12 | // | |
13 | ||
14 | /* | |
15 | * Hardware interface for generic Intel audio DSP HDA IP | |
16 | */ | |
17 | ||
18 | #include <sound/hdaudio_ext.h> | |
19 | #include <sound/hda_register.h> | |
20 | #include "../ops.h" | |
21 | #include "hda.h" | |
22 | ||
23 | /* | |
24 | * DSP Core control. | |
25 | */ | |
26 | ||
27 | int hda_dsp_core_reset_enter(struct snd_sof_dev *sdev, unsigned int core_mask) | |
28 | { | |
29 | u32 adspcs; | |
30 | u32 reset; | |
31 | int ret; | |
32 | ||
33 | /* set reset bits for cores */ | |
34 | reset = HDA_DSP_ADSPCS_CRST_MASK(core_mask); | |
35 | snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, | |
36 | HDA_DSP_REG_ADSPCS, | |
37 | reset, reset), | |
38 | ||
39 | /* poll with timeout to check if operation successful */ | |
40 | ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, | |
41 | HDA_DSP_REG_ADSPCS, adspcs, | |
42 | ((adspcs & reset) == reset), | |
43 | HDA_DSP_REG_POLL_INTERVAL_US, | |
44 | HDA_DSP_RESET_TIMEOUT_US); | |
6a414489 PLB |
45 | if (ret < 0) { |
46 | dev_err(sdev->dev, | |
47 | "error: %s: timeout on HDA_DSP_REG_ADSPCS read\n", | |
48 | __func__); | |
49 | return ret; | |
50 | } | |
747503b1 LG |
51 | |
52 | /* has core entered reset ? */ | |
53 | adspcs = snd_sof_dsp_read(sdev, HDA_DSP_BAR, | |
54 | HDA_DSP_REG_ADSPCS); | |
55 | if ((adspcs & HDA_DSP_ADSPCS_CRST_MASK(core_mask)) != | |
56 | HDA_DSP_ADSPCS_CRST_MASK(core_mask)) { | |
57 | dev_err(sdev->dev, | |
58 | "error: reset enter failed: core_mask %x adspcs 0x%x\n", | |
59 | core_mask, adspcs); | |
60 | ret = -EIO; | |
61 | } | |
62 | ||
63 | return ret; | |
64 | } | |
65 | ||
66 | int hda_dsp_core_reset_leave(struct snd_sof_dev *sdev, unsigned int core_mask) | |
67 | { | |
68 | unsigned int crst; | |
69 | u32 adspcs; | |
70 | int ret; | |
71 | ||
72 | /* clear reset bits for cores */ | |
73 | snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, | |
74 | HDA_DSP_REG_ADSPCS, | |
75 | HDA_DSP_ADSPCS_CRST_MASK(core_mask), | |
76 | 0); | |
77 | ||
78 | /* poll with timeout to check if operation successful */ | |
79 | crst = HDA_DSP_ADSPCS_CRST_MASK(core_mask); | |
80 | ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, | |
81 | HDA_DSP_REG_ADSPCS, adspcs, | |
82 | !(adspcs & crst), | |
83 | HDA_DSP_REG_POLL_INTERVAL_US, | |
84 | HDA_DSP_RESET_TIMEOUT_US); | |
85 | ||
6a414489 PLB |
86 | if (ret < 0) { |
87 | dev_err(sdev->dev, | |
88 | "error: %s: timeout on HDA_DSP_REG_ADSPCS read\n", | |
89 | __func__); | |
90 | return ret; | |
91 | } | |
92 | ||
747503b1 LG |
93 | /* has core left reset ? */ |
94 | adspcs = snd_sof_dsp_read(sdev, HDA_DSP_BAR, | |
95 | HDA_DSP_REG_ADSPCS); | |
96 | if ((adspcs & HDA_DSP_ADSPCS_CRST_MASK(core_mask)) != 0) { | |
97 | dev_err(sdev->dev, | |
98 | "error: reset leave failed: core_mask %x adspcs 0x%x\n", | |
99 | core_mask, adspcs); | |
100 | ret = -EIO; | |
101 | } | |
102 | ||
103 | return ret; | |
104 | } | |
105 | ||
106 | int hda_dsp_core_stall_reset(struct snd_sof_dev *sdev, unsigned int core_mask) | |
107 | { | |
108 | /* stall core */ | |
109 | snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, | |
110 | HDA_DSP_REG_ADSPCS, | |
111 | HDA_DSP_ADSPCS_CSTALL_MASK(core_mask), | |
112 | HDA_DSP_ADSPCS_CSTALL_MASK(core_mask)); | |
113 | ||
114 | /* set reset state */ | |
115 | return hda_dsp_core_reset_enter(sdev, core_mask); | |
116 | } | |
117 | ||
118 | int hda_dsp_core_run(struct snd_sof_dev *sdev, unsigned int core_mask) | |
119 | { | |
120 | int ret; | |
121 | ||
122 | /* leave reset state */ | |
123 | ret = hda_dsp_core_reset_leave(sdev, core_mask); | |
124 | if (ret < 0) | |
125 | return ret; | |
126 | ||
127 | /* run core */ | |
128 | dev_dbg(sdev->dev, "unstall/run core: core_mask = %x\n", core_mask); | |
129 | snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, | |
130 | HDA_DSP_REG_ADSPCS, | |
131 | HDA_DSP_ADSPCS_CSTALL_MASK(core_mask), | |
132 | 0); | |
133 | ||
134 | /* is core now running ? */ | |
135 | if (!hda_dsp_core_is_enabled(sdev, core_mask)) { | |
136 | hda_dsp_core_stall_reset(sdev, core_mask); | |
137 | dev_err(sdev->dev, "error: DSP start core failed: core_mask %x\n", | |
138 | core_mask); | |
139 | ret = -EIO; | |
140 | } | |
141 | ||
142 | return ret; | |
143 | } | |
144 | ||
145 | /* | |
146 | * Power Management. | |
147 | */ | |
148 | ||
149 | int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask) | |
150 | { | |
151 | unsigned int cpa; | |
152 | u32 adspcs; | |
153 | int ret; | |
154 | ||
155 | /* update bits */ | |
156 | snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPCS, | |
157 | HDA_DSP_ADSPCS_SPA_MASK(core_mask), | |
158 | HDA_DSP_ADSPCS_SPA_MASK(core_mask)); | |
159 | ||
160 | /* poll with timeout to check if operation successful */ | |
161 | cpa = HDA_DSP_ADSPCS_CPA_MASK(core_mask); | |
162 | ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, | |
163 | HDA_DSP_REG_ADSPCS, adspcs, | |
164 | (adspcs & cpa) == cpa, | |
165 | HDA_DSP_REG_POLL_INTERVAL_US, | |
166 | HDA_DSP_RESET_TIMEOUT_US); | |
6a414489 PLB |
167 | if (ret < 0) { |
168 | dev_err(sdev->dev, | |
169 | "error: %s: timeout on HDA_DSP_REG_ADSPCS read\n", | |
170 | __func__); | |
171 | return ret; | |
172 | } | |
747503b1 LG |
173 | |
174 | /* did core power up ? */ | |
175 | adspcs = snd_sof_dsp_read(sdev, HDA_DSP_BAR, | |
176 | HDA_DSP_REG_ADSPCS); | |
177 | if ((adspcs & HDA_DSP_ADSPCS_CPA_MASK(core_mask)) != | |
178 | HDA_DSP_ADSPCS_CPA_MASK(core_mask)) { | |
179 | dev_err(sdev->dev, | |
180 | "error: power up core failed core_mask %xadspcs 0x%x\n", | |
181 | core_mask, adspcs); | |
182 | ret = -EIO; | |
183 | } | |
184 | ||
185 | return ret; | |
186 | } | |
187 | ||
188 | int hda_dsp_core_power_down(struct snd_sof_dev *sdev, unsigned int core_mask) | |
189 | { | |
190 | u32 adspcs; | |
6a414489 | 191 | int ret; |
747503b1 LG |
192 | |
193 | /* update bits */ | |
194 | snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, | |
195 | HDA_DSP_REG_ADSPCS, | |
196 | HDA_DSP_ADSPCS_SPA_MASK(core_mask), 0); | |
197 | ||
6a414489 | 198 | ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, |
747503b1 LG |
199 | HDA_DSP_REG_ADSPCS, adspcs, |
200 | !(adspcs & HDA_DSP_ADSPCS_SPA_MASK(core_mask)), | |
201 | HDA_DSP_REG_POLL_INTERVAL_US, | |
202 | HDA_DSP_PD_TIMEOUT * USEC_PER_MSEC); | |
6a414489 PLB |
203 | if (ret < 0) |
204 | dev_err(sdev->dev, | |
205 | "error: %s: timeout on HDA_DSP_REG_ADSPCS read\n", | |
206 | __func__); | |
207 | ||
208 | return ret; | |
747503b1 LG |
209 | } |
210 | ||
211 | bool hda_dsp_core_is_enabled(struct snd_sof_dev *sdev, | |
212 | unsigned int core_mask) | |
213 | { | |
214 | int val; | |
215 | bool is_enable; | |
216 | ||
217 | val = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPCS); | |
218 | ||
219 | is_enable = ((val & HDA_DSP_ADSPCS_CPA_MASK(core_mask)) && | |
220 | (val & HDA_DSP_ADSPCS_SPA_MASK(core_mask)) && | |
221 | !(val & HDA_DSP_ADSPCS_CRST_MASK(core_mask)) && | |
222 | !(val & HDA_DSP_ADSPCS_CSTALL_MASK(core_mask))); | |
223 | ||
224 | dev_dbg(sdev->dev, "DSP core(s) enabled? %d : core_mask %x\n", | |
225 | is_enable, core_mask); | |
226 | ||
227 | return is_enable; | |
228 | } | |
229 | ||
230 | int hda_dsp_enable_core(struct snd_sof_dev *sdev, unsigned int core_mask) | |
231 | { | |
232 | int ret; | |
233 | ||
234 | /* return if core is already enabled */ | |
235 | if (hda_dsp_core_is_enabled(sdev, core_mask)) | |
236 | return 0; | |
237 | ||
238 | /* power up */ | |
239 | ret = hda_dsp_core_power_up(sdev, core_mask); | |
240 | if (ret < 0) { | |
241 | dev_err(sdev->dev, "error: dsp core power up failed: core_mask %x\n", | |
242 | core_mask); | |
243 | return ret; | |
244 | } | |
245 | ||
246 | return hda_dsp_core_run(sdev, core_mask); | |
247 | } | |
248 | ||
249 | int hda_dsp_core_reset_power_down(struct snd_sof_dev *sdev, | |
250 | unsigned int core_mask) | |
251 | { | |
252 | int ret; | |
253 | ||
254 | /* place core in reset prior to power down */ | |
255 | ret = hda_dsp_core_stall_reset(sdev, core_mask); | |
256 | if (ret < 0) { | |
257 | dev_err(sdev->dev, "error: dsp core reset failed: core_mask %x\n", | |
258 | core_mask); | |
259 | return ret; | |
260 | } | |
261 | ||
262 | /* power down core */ | |
263 | ret = hda_dsp_core_power_down(sdev, core_mask); | |
264 | if (ret < 0) { | |
265 | dev_err(sdev->dev, "error: dsp core power down fail mask %x: %d\n", | |
266 | core_mask, ret); | |
267 | return ret; | |
268 | } | |
269 | ||
270 | /* make sure we are in OFF state */ | |
271 | if (hda_dsp_core_is_enabled(sdev, core_mask)) { | |
272 | dev_err(sdev->dev, "error: dsp core disable fail mask %x: %d\n", | |
273 | core_mask, ret); | |
274 | ret = -EIO; | |
275 | } | |
276 | ||
277 | return ret; | |
278 | } | |
279 | ||
280 | void hda_dsp_ipc_int_enable(struct snd_sof_dev *sdev) | |
281 | { | |
282 | struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; | |
283 | const struct sof_intel_dsp_desc *chip = hda->desc; | |
284 | ||
285 | /* enable IPC DONE and BUSY interrupts */ | |
286 | snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl, | |
287 | HDA_DSP_REG_HIPCCTL_DONE | HDA_DSP_REG_HIPCCTL_BUSY, | |
288 | HDA_DSP_REG_HIPCCTL_DONE | HDA_DSP_REG_HIPCCTL_BUSY); | |
289 | ||
290 | /* enable IPC interrupt */ | |
291 | snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, | |
292 | HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC); | |
293 | } | |
294 | ||
295 | void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev) | |
296 | { | |
297 | struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; | |
298 | const struct sof_intel_dsp_desc *chip = hda->desc; | |
299 | ||
300 | /* disable IPC interrupt */ | |
301 | snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, | |
302 | HDA_DSP_ADSPIC_IPC, 0); | |
303 | ||
304 | /* disable IPC BUSY and DONE interrupt */ | |
305 | snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl, | |
306 | HDA_DSP_REG_HIPCCTL_BUSY | HDA_DSP_REG_HIPCCTL_DONE, 0); | |
307 | } | |
308 | ||
62f8f766 KJ |
309 | static int hda_dsp_wait_d0i3c_done(struct snd_sof_dev *sdev, int retry) |
310 | { | |
311 | struct hdac_bus *bus = sof_to_bus(sdev); | |
312 | ||
313 | while (snd_hdac_chip_readb(bus, VS_D0I3C) & SOF_HDA_VS_D0I3C_CIP) { | |
314 | if (!retry--) | |
315 | return -ETIMEDOUT; | |
316 | usleep_range(10, 15); | |
317 | } | |
318 | ||
319 | return 0; | |
320 | } | |
321 | ||
322 | int hda_dsp_set_power_state(struct snd_sof_dev *sdev, | |
323 | enum sof_d0_substate d0_substate) | |
324 | { | |
325 | struct hdac_bus *bus = sof_to_bus(sdev); | |
62f8f766 KJ |
326 | int ret; |
327 | u8 value; | |
328 | ||
329 | /* Write to D0I3C after Command-In-Progress bit is cleared */ | |
92f4beb7 | 330 | ret = hda_dsp_wait_d0i3c_done(sdev, HDA_DSP_REG_POLL_RETRY_COUNT); |
62f8f766 | 331 | if (ret < 0) { |
aae7c82d | 332 | dev_err(bus->dev, "CIP timeout before D0I3C update!\n"); |
62f8f766 KJ |
333 | return ret; |
334 | } | |
335 | ||
336 | /* Update D0I3C register */ | |
337 | value = d0_substate == SOF_DSP_D0I3 ? SOF_HDA_VS_D0I3C_I3 : 0; | |
338 | snd_hdac_chip_updateb(bus, VS_D0I3C, SOF_HDA_VS_D0I3C_I3, value); | |
339 | ||
340 | /* Wait for cmd in progress to be cleared before exiting the function */ | |
92f4beb7 | 341 | ret = hda_dsp_wait_d0i3c_done(sdev, HDA_DSP_REG_POLL_RETRY_COUNT); |
62f8f766 | 342 | if (ret < 0) { |
aae7c82d | 343 | dev_err(bus->dev, "CIP timeout after D0I3C update!\n"); |
62f8f766 KJ |
344 | return ret; |
345 | } | |
346 | ||
347 | dev_vdbg(bus->dev, "D0I3C updated, register = 0x%x\n", | |
348 | snd_hdac_chip_readb(bus, VS_D0I3C)); | |
349 | ||
350 | return 0; | |
351 | } | |
352 | ||
1c38c922 | 353 | static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend) |
747503b1 LG |
354 | { |
355 | struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; | |
356 | const struct sof_intel_dsp_desc *chip = hda->desc; | |
357 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) | |
358 | struct hdac_bus *bus = sof_to_bus(sdev); | |
359 | #endif | |
360 | int ret; | |
361 | ||
362 | /* disable IPC interrupts */ | |
363 | hda_dsp_ipc_int_disable(sdev); | |
364 | ||
365 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) | |
fd15f2f5 RW |
366 | if (runtime_suspend) |
367 | hda_codec_jack_wake_enable(sdev); | |
368 | ||
747503b1 LG |
369 | /* power down all hda link */ |
370 | snd_hdac_ext_bus_link_power_down_all(bus); | |
371 | #endif | |
372 | ||
373 | /* power down DSP */ | |
374 | ret = hda_dsp_core_reset_power_down(sdev, chip->cores_mask); | |
375 | if (ret < 0) { | |
376 | dev_err(sdev->dev, | |
377 | "error: failed to power down core during suspend\n"); | |
378 | return ret; | |
379 | } | |
380 | ||
747503b1 | 381 | /* disable ppcap interrupt */ |
24b6ff68 ZY |
382 | hda_dsp_ctrl_ppcap_enable(sdev, false); |
383 | hda_dsp_ctrl_ppcap_int_enable(sdev, false); | |
747503b1 | 384 | |
9a50ee58 ZY |
385 | /* disable hda bus irq and streams */ |
386 | hda_dsp_ctrl_stop_chip(sdev); | |
747503b1 LG |
387 | |
388 | /* disable LP retention mode */ | |
389 | snd_sof_pci_update_bits(sdev, PCI_PGCTL, | |
390 | PCI_PGCTL_LSRMD_MASK, PCI_PGCTL_LSRMD_MASK); | |
391 | ||
392 | /* reset controller */ | |
393 | ret = hda_dsp_ctrl_link_reset(sdev, true); | |
394 | if (ret < 0) { | |
395 | dev_err(sdev->dev, | |
396 | "error: failed to reset controller during suspend\n"); | |
397 | return ret; | |
398 | } | |
399 | ||
400 | return 0; | |
401 | } | |
402 | ||
fd15f2f5 | 403 | static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume) |
747503b1 LG |
404 | { |
405 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) | |
406 | struct hdac_bus *bus = sof_to_bus(sdev); | |
407 | struct hdac_ext_link *hlink = NULL; | |
408 | #endif | |
409 | int ret; | |
410 | ||
411 | /* | |
412 | * clear TCSEL to clear playback on some HD Audio | |
413 | * codecs. PCI TCSEL is defined in the Intel manuals. | |
414 | */ | |
415 | snd_sof_pci_update_bits(sdev, PCI_TCSEL, 0x07, 0); | |
416 | ||
747503b1 LG |
417 | /* reset and start hda controller */ |
418 | ret = hda_dsp_ctrl_init_chip(sdev, true); | |
419 | if (ret < 0) { | |
420 | dev_err(sdev->dev, | |
421 | "error: failed to start controller after resume\n"); | |
422 | return ret; | |
423 | } | |
424 | ||
fd15f2f5 RW |
425 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) |
426 | /* check jack status */ | |
427 | if (runtime_resume) | |
428 | hda_codec_jack_check(sdev); | |
6aa232e1 RW |
429 | |
430 | /* turn off the links that were off before suspend */ | |
431 | list_for_each_entry(hlink, &bus->hlink_list, list) { | |
432 | if (!hlink->ref_count) | |
433 | snd_hdac_ext_bus_link_power_down(hlink); | |
434 | } | |
435 | ||
436 | /* check dma status and clean up CORB/RIRB buffers */ | |
437 | if (!bus->cmd_dma_state) | |
438 | snd_hdac_bus_stop_cmd_io(bus); | |
24b6ff68 | 439 | #endif |
747503b1 LG |
440 | |
441 | /* enable ppcap interrupt */ | |
442 | hda_dsp_ctrl_ppcap_enable(sdev, true); | |
443 | hda_dsp_ctrl_ppcap_int_enable(sdev, true); | |
747503b1 | 444 | |
747503b1 LG |
445 | return 0; |
446 | } | |
447 | ||
448 | int hda_dsp_resume(struct snd_sof_dev *sdev) | |
449 | { | |
450 | /* init hda controller. DSP cores will be powered up during fw boot */ | |
fd15f2f5 | 451 | return hda_resume(sdev, false); |
747503b1 LG |
452 | } |
453 | ||
454 | int hda_dsp_runtime_resume(struct snd_sof_dev *sdev) | |
455 | { | |
456 | /* init hda controller. DSP cores will be powered up during fw boot */ | |
fd15f2f5 | 457 | return hda_resume(sdev, true); |
747503b1 LG |
458 | } |
459 | ||
87a6fe80 KV |
460 | int hda_dsp_runtime_idle(struct snd_sof_dev *sdev) |
461 | { | |
462 | struct hdac_bus *hbus = sof_to_bus(sdev); | |
463 | ||
464 | if (hbus->codec_powered) { | |
465 | dev_dbg(sdev->dev, "some codecs still powered (%08X), not idle\n", | |
466 | (unsigned int)hbus->codec_powered); | |
467 | return -EBUSY; | |
468 | } | |
469 | ||
470 | return 0; | |
471 | } | |
472 | ||
1c38c922 | 473 | int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev) |
747503b1 LG |
474 | { |
475 | /* stop hda controller and power dsp off */ | |
1c38c922 | 476 | return hda_suspend(sdev, true); |
747503b1 LG |
477 | } |
478 | ||
1c38c922 | 479 | int hda_dsp_suspend(struct snd_sof_dev *sdev) |
747503b1 LG |
480 | { |
481 | struct hdac_bus *bus = sof_to_bus(sdev); | |
482 | int ret; | |
483 | ||
484 | /* stop hda controller and power dsp off */ | |
1c38c922 | 485 | ret = hda_suspend(sdev, false); |
747503b1 LG |
486 | if (ret < 0) { |
487 | dev_err(bus->dev, "error: suspending dsp\n"); | |
488 | return ret; | |
489 | } | |
490 | ||
491 | return 0; | |
492 | } | |
ed3baacd | 493 | |
7077a07a | 494 | int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev) |
ed3baacd | 495 | { |
7077a07a | 496 | #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) |
a3ebccb5 | 497 | struct hdac_bus *bus = sof_to_bus(sdev); |
7077a07a | 498 | struct snd_soc_pcm_runtime *rtd; |
a3ebccb5 | 499 | struct hdac_ext_stream *stream; |
7077a07a | 500 | struct hdac_ext_link *link; |
a3ebccb5 | 501 | struct hdac_stream *s; |
7077a07a RS |
502 | const char *name; |
503 | int stream_tag; | |
7077a07a | 504 | |
ed3baacd RS |
505 | /* set internal flag for BE */ |
506 | list_for_each_entry(s, &bus->stream_list, list) { | |
507 | stream = stream_to_hdac_ext_stream(s); | |
a3ebccb5 | 508 | |
7077a07a | 509 | /* |
934bf822 RW |
510 | * clear stream. This should already be taken care for running |
511 | * streams when the SUSPEND trigger is called. But paused | |
512 | * streams do not get suspended, so this needs to be done | |
513 | * explicitly during suspend. | |
7077a07a RS |
514 | */ |
515 | if (stream->link_substream) { | |
516 | rtd = snd_pcm_substream_chip(stream->link_substream); | |
517 | name = rtd->codec_dai->component->name; | |
518 | link = snd_hdac_ext_bus_get_link(bus, name); | |
519 | if (!link) | |
520 | return -EINVAL; | |
810dbea3 RW |
521 | |
522 | stream->link_prepared = 0; | |
523 | ||
524 | if (hdac_stream(stream)->direction == | |
525 | SNDRV_PCM_STREAM_CAPTURE) | |
526 | continue; | |
527 | ||
7077a07a RS |
528 | stream_tag = hdac_stream(stream)->stream_tag; |
529 | snd_hdac_ext_link_clear_stream_id(link, stream_tag); | |
7077a07a | 530 | } |
ed3baacd | 531 | } |
a3ebccb5 | 532 | #endif |
7077a07a | 533 | return 0; |
ed3baacd | 534 | } |