1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // |
3 | // soc-component.c |
4 | // |
5 | // Copyright 2009-2011 Wolfson Microelectronics PLC. |
6 | // Copyright (C) 2019 Renesas Electronics Corp. |
7 | // |
8 | // Mark Brown <broonie@opensource.wolfsonmicro.com> |
9 | // Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> |
10 | // |
11 | #include <linux/module.h> |
12 | #include <linux/pm_runtime.h> |
13 | #include <sound/soc.h> |
14 | #include <linux/bitops.h> |
15 | |
16 | #define soc_component_ret(dai, ret) _soc_component_ret(dai, __func__, ret, -1) |
17 | #define soc_component_ret_reg_rw(dai, ret, reg) _soc_component_ret(dai, __func__, ret, reg) |
18 | static inline int _soc_component_ret(struct snd_soc_component *component, |
19 | const char *func, int ret, int reg) |
20 | { |
21 | /* Positive/Zero values are not errors */ |
22 | if (ret >= 0) |
23 | return ret; |
24 | |
25 | /* Negative values might be errors */ |
26 | switch (ret) { |
27 | case -EPROBE_DEFER: |
28 | case -ENOTSUPP: |
29 | break; |
30 | default: |
31 | if (reg == -1) |
32 | dev_err(component->dev, |
33 | "ASoC: error at %s on %s: %d\n" , |
34 | func, component->name, ret); |
35 | else |
36 | dev_err(component->dev, |
37 | "ASoC: error at %s on %s for register: [0x%08x] %d\n" , |
38 | func, component->name, reg, ret); |
39 | } |
40 | |
41 | return ret; |
42 | } |
43 | |
44 | static inline int soc_component_field_shift(struct snd_soc_component *component, |
45 | unsigned int mask) |
46 | { |
47 | if (!mask) { |
48 | dev_err(component->dev, "ASoC: error field mask is zero for %s\n" , |
49 | component->name); |
50 | return 0; |
51 | } |
52 | |
53 | return (ffs(mask) - 1); |
54 | } |
55 | |
56 | /* |
57 | * We might want to check substream by using list. |
58 | * In such case, we can update these macros. |
59 | */ |
60 | #define soc_component_mark_push(component, substream, tgt) ((component)->mark_##tgt = substream) |
61 | #define soc_component_mark_pop(component, substream, tgt) ((component)->mark_##tgt = NULL) |
62 | #define soc_component_mark_match(component, substream, tgt) ((component)->mark_##tgt == substream) |
63 | |
64 | void snd_soc_component_set_aux(struct snd_soc_component *component, |
65 | struct snd_soc_aux_dev *aux) |
66 | { |
67 | component->init = (aux) ? aux->init : NULL; |
68 | } |
69 | |
70 | int snd_soc_component_init(struct snd_soc_component *component) |
71 | { |
72 | int ret = 0; |
73 | |
74 | if (component->init) |
75 | ret = component->init(component); |
76 | |
77 | return soc_component_ret(component, ret); |
78 | } |
79 | |
80 | /** |
81 | * snd_soc_component_set_sysclk - configure COMPONENT system or master clock. |
82 | * @component: COMPONENT |
83 | * @clk_id: DAI specific clock ID |
84 | * @source: Source for the clock |
85 | * @freq: new clock frequency in Hz |
86 | * @dir: new clock direction - input/output. |
87 | * |
88 | * Configures the CODEC master (MCLK) or system (SYSCLK) clocking. |
89 | */ |
90 | int snd_soc_component_set_sysclk(struct snd_soc_component *component, |
91 | int clk_id, int source, unsigned int freq, |
92 | int dir) |
93 | { |
94 | int ret = -ENOTSUPP; |
95 | |
96 | if (component->driver->set_sysclk) |
97 | ret = component->driver->set_sysclk(component, clk_id, source, |
98 | freq, dir); |
99 | |
100 | return soc_component_ret(component, ret); |
101 | } |
102 | EXPORT_SYMBOL_GPL(snd_soc_component_set_sysclk); |
103 | |
104 | /* |
105 | * snd_soc_component_set_pll - configure component PLL. |
106 | * @component: COMPONENT |
107 | * @pll_id: DAI specific PLL ID |
108 | * @source: DAI specific source for the PLL |
109 | * @freq_in: PLL input clock frequency in Hz |
110 | * @freq_out: requested PLL output clock frequency in Hz |
111 | * |
112 | * Configures and enables PLL to generate output clock based on input clock. |
113 | */ |
114 | int snd_soc_component_set_pll(struct snd_soc_component *component, int pll_id, |
115 | int source, unsigned int freq_in, |
116 | unsigned int freq_out) |
117 | { |
118 | int ret = -EINVAL; |
119 | |
120 | if (component->driver->set_pll) |
121 | ret = component->driver->set_pll(component, pll_id, source, |
122 | freq_in, freq_out); |
123 | |
124 | return soc_component_ret(component, ret); |
125 | } |
126 | EXPORT_SYMBOL_GPL(snd_soc_component_set_pll); |
127 | |
128 | void snd_soc_component_seq_notifier(struct snd_soc_component *component, |
129 | enum snd_soc_dapm_type type, int subseq) |
130 | { |
131 | if (component->driver->seq_notifier) |
132 | component->driver->seq_notifier(component, type, subseq); |
133 | } |
134 | |
135 | int snd_soc_component_stream_event(struct snd_soc_component *component, |
136 | int event) |
137 | { |
138 | int ret = 0; |
139 | |
140 | if (component->driver->stream_event) |
141 | ret = component->driver->stream_event(component, event); |
142 | |
143 | return soc_component_ret(component, ret); |
144 | } |
145 | |
146 | int snd_soc_component_set_bias_level(struct snd_soc_component *component, |
147 | enum snd_soc_bias_level level) |
148 | { |
149 | int ret = 0; |
150 | |
151 | if (component->driver->set_bias_level) |
152 | ret = component->driver->set_bias_level(component, level); |
153 | |
154 | return soc_component_ret(component, ret); |
155 | } |
156 | |
157 | int snd_soc_component_enable_pin(struct snd_soc_component *component, |
158 | const char *pin) |
159 | { |
160 | struct snd_soc_dapm_context *dapm = |
161 | snd_soc_component_get_dapm(component); |
162 | return snd_soc_dapm_enable_pin(dapm, pin); |
163 | } |
164 | EXPORT_SYMBOL_GPL(snd_soc_component_enable_pin); |
165 | |
166 | int snd_soc_component_enable_pin_unlocked(struct snd_soc_component *component, |
167 | const char *pin) |
168 | { |
169 | struct snd_soc_dapm_context *dapm = |
170 | snd_soc_component_get_dapm(component); |
171 | return snd_soc_dapm_enable_pin_unlocked(dapm, pin); |
172 | } |
173 | EXPORT_SYMBOL_GPL(snd_soc_component_enable_pin_unlocked); |
174 | |
175 | int snd_soc_component_disable_pin(struct snd_soc_component *component, |
176 | const char *pin) |
177 | { |
178 | struct snd_soc_dapm_context *dapm = |
179 | snd_soc_component_get_dapm(component); |
180 | return snd_soc_dapm_disable_pin(dapm, pin); |
181 | } |
182 | EXPORT_SYMBOL_GPL(snd_soc_component_disable_pin); |
183 | |
184 | int snd_soc_component_disable_pin_unlocked(struct snd_soc_component *component, |
185 | const char *pin) |
186 | { |
187 | struct snd_soc_dapm_context *dapm = |
188 | snd_soc_component_get_dapm(component); |
189 | return snd_soc_dapm_disable_pin_unlocked(dapm, pin); |
190 | } |
191 | EXPORT_SYMBOL_GPL(snd_soc_component_disable_pin_unlocked); |
192 | |
193 | int snd_soc_component_nc_pin(struct snd_soc_component *component, |
194 | const char *pin) |
195 | { |
196 | struct snd_soc_dapm_context *dapm = |
197 | snd_soc_component_get_dapm(component); |
198 | return snd_soc_dapm_nc_pin(dapm, pin); |
199 | } |
200 | EXPORT_SYMBOL_GPL(snd_soc_component_nc_pin); |
201 | |
202 | int snd_soc_component_nc_pin_unlocked(struct snd_soc_component *component, |
203 | const char *pin) |
204 | { |
205 | struct snd_soc_dapm_context *dapm = |
206 | snd_soc_component_get_dapm(component); |
207 | return snd_soc_dapm_nc_pin_unlocked(dapm, pin); |
208 | } |
209 | EXPORT_SYMBOL_GPL(snd_soc_component_nc_pin_unlocked); |
210 | |
211 | int snd_soc_component_get_pin_status(struct snd_soc_component *component, |
212 | const char *pin) |
213 | { |
214 | struct snd_soc_dapm_context *dapm = |
215 | snd_soc_component_get_dapm(component); |
216 | return snd_soc_dapm_get_pin_status(dapm, pin); |
217 | } |
218 | EXPORT_SYMBOL_GPL(snd_soc_component_get_pin_status); |
219 | |
220 | int snd_soc_component_force_enable_pin(struct snd_soc_component *component, |
221 | const char *pin) |
222 | { |
223 | struct snd_soc_dapm_context *dapm = |
224 | snd_soc_component_get_dapm(component); |
225 | return snd_soc_dapm_force_enable_pin(dapm, pin); |
226 | } |
227 | EXPORT_SYMBOL_GPL(snd_soc_component_force_enable_pin); |
228 | |
229 | int snd_soc_component_force_enable_pin_unlocked( |
230 | struct snd_soc_component *component, |
231 | const char *pin) |
232 | { |
233 | struct snd_soc_dapm_context *dapm = |
234 | snd_soc_component_get_dapm(component); |
235 | return snd_soc_dapm_force_enable_pin_unlocked(dapm, pin); |
236 | } |
237 | EXPORT_SYMBOL_GPL(snd_soc_component_force_enable_pin_unlocked); |
238 | |
239 | int snd_soc_component_notify_control(struct snd_soc_component *component, |
240 | const char * const ctl) |
241 | { |
242 | char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; |
243 | struct snd_kcontrol *kctl; |
244 | |
245 | /* When updating, change also snd_soc_dapm_widget_name_cmp() */ |
246 | if (component->name_prefix) |
247 | snprintf(buf: name, ARRAY_SIZE(name), fmt: "%s %s" , component->name_prefix, ctl); |
248 | else |
249 | snprintf(buf: name, ARRAY_SIZE(name), fmt: "%s" , ctl); |
250 | |
251 | kctl = snd_soc_card_get_kcontrol(soc_card: component->card, name); |
252 | if (!kctl) |
253 | return soc_component_ret(component, -EINVAL); |
254 | |
255 | snd_ctl_notify(card: component->card->snd_card, |
256 | SNDRV_CTL_EVENT_MASK_VALUE, id: &kctl->id); |
257 | |
258 | return 0; |
259 | } |
260 | EXPORT_SYMBOL_GPL(snd_soc_component_notify_control); |
261 | |
262 | /** |
263 | * snd_soc_component_set_jack - configure component jack. |
264 | * @component: COMPONENTs |
265 | * @jack: structure to use for the jack |
266 | * @data: can be used if codec driver need extra data for configuring jack |
267 | * |
268 | * Configures and enables jack detection function. |
269 | */ |
270 | int snd_soc_component_set_jack(struct snd_soc_component *component, |
271 | struct snd_soc_jack *jack, void *data) |
272 | { |
273 | int ret = -ENOTSUPP; |
274 | |
275 | if (component->driver->set_jack) |
276 | ret = component->driver->set_jack(component, jack, data); |
277 | |
278 | return soc_component_ret(component, ret); |
279 | } |
280 | EXPORT_SYMBOL_GPL(snd_soc_component_set_jack); |
281 | |
282 | /** |
283 | * snd_soc_component_get_jack_type |
284 | * @component: COMPONENTs |
285 | * |
286 | * Returns the jack type of the component |
287 | * This can either be the supported type or one read from |
288 | * devicetree with the property: jack-type. |
289 | */ |
290 | int snd_soc_component_get_jack_type( |
291 | struct snd_soc_component *component) |
292 | { |
293 | int ret = -ENOTSUPP; |
294 | |
295 | if (component->driver->get_jack_type) |
296 | ret = component->driver->get_jack_type(component); |
297 | |
298 | return soc_component_ret(component, ret); |
299 | } |
300 | EXPORT_SYMBOL_GPL(snd_soc_component_get_jack_type); |
301 | |
302 | int snd_soc_component_module_get(struct snd_soc_component *component, |
303 | void *mark, int upon_open) |
304 | { |
305 | int ret = 0; |
306 | |
307 | if (component->driver->module_get_upon_open == !!upon_open && |
308 | !try_module_get(module: component->dev->driver->owner)) |
309 | ret = -ENODEV; |
310 | |
311 | /* mark module if succeeded */ |
312 | if (ret == 0) |
313 | soc_component_mark_push(component, mark, module); |
314 | |
315 | return soc_component_ret(component, ret); |
316 | } |
317 | |
318 | void snd_soc_component_module_put(struct snd_soc_component *component, |
319 | void *mark, int upon_open, int rollback) |
320 | { |
321 | if (rollback && !soc_component_mark_match(component, mark, module)) |
322 | return; |
323 | |
324 | if (component->driver->module_get_upon_open == !!upon_open) |
325 | module_put(module: component->dev->driver->owner); |
326 | |
327 | /* remove the mark from module */ |
328 | soc_component_mark_pop(component, mark, module); |
329 | } |
330 | |
331 | int snd_soc_component_open(struct snd_soc_component *component, |
332 | struct snd_pcm_substream *substream) |
333 | { |
334 | int ret = 0; |
335 | |
336 | if (component->driver->open) |
337 | ret = component->driver->open(component, substream); |
338 | |
339 | /* mark substream if succeeded */ |
340 | if (ret == 0) |
341 | soc_component_mark_push(component, substream, open); |
342 | |
343 | return soc_component_ret(component, ret); |
344 | } |
345 | |
346 | int snd_soc_component_close(struct snd_soc_component *component, |
347 | struct snd_pcm_substream *substream, |
348 | int rollback) |
349 | { |
350 | int ret = 0; |
351 | |
352 | if (rollback && !soc_component_mark_match(component, substream, open)) |
353 | return 0; |
354 | |
355 | if (component->driver->close) |
356 | ret = component->driver->close(component, substream); |
357 | |
358 | /* remove marked substream */ |
359 | soc_component_mark_pop(component, substream, open); |
360 | |
361 | return soc_component_ret(component, ret); |
362 | } |
363 | |
364 | void snd_soc_component_suspend(struct snd_soc_component *component) |
365 | { |
366 | if (component->driver->suspend) |
367 | component->driver->suspend(component); |
368 | component->suspended = 1; |
369 | } |
370 | |
371 | void snd_soc_component_resume(struct snd_soc_component *component) |
372 | { |
373 | if (component->driver->resume) |
374 | component->driver->resume(component); |
375 | component->suspended = 0; |
376 | } |
377 | |
378 | int snd_soc_component_is_suspended(struct snd_soc_component *component) |
379 | { |
380 | return component->suspended; |
381 | } |
382 | |
383 | int snd_soc_component_probe(struct snd_soc_component *component) |
384 | { |
385 | int ret = 0; |
386 | |
387 | if (component->driver->probe) |
388 | ret = component->driver->probe(component); |
389 | |
390 | return soc_component_ret(component, ret); |
391 | } |
392 | |
393 | void snd_soc_component_remove(struct snd_soc_component *component) |
394 | { |
395 | if (component->driver->remove) |
396 | component->driver->remove(component); |
397 | } |
398 | |
399 | int snd_soc_component_of_xlate_dai_id(struct snd_soc_component *component, |
400 | struct device_node *ep) |
401 | { |
402 | int ret = -ENOTSUPP; |
403 | |
404 | if (component->driver->of_xlate_dai_id) |
405 | ret = component->driver->of_xlate_dai_id(component, ep); |
406 | |
407 | return soc_component_ret(component, ret); |
408 | } |
409 | |
410 | int snd_soc_component_of_xlate_dai_name(struct snd_soc_component *component, |
411 | const struct of_phandle_args *args, |
412 | const char **dai_name) |
413 | { |
414 | if (component->driver->of_xlate_dai_name) |
415 | return component->driver->of_xlate_dai_name(component, |
416 | args, dai_name); |
417 | /* |
418 | * Don't use soc_component_ret here because we may not want to report |
419 | * the error just yet. If a device has more than one component, the |
420 | * first may not match and we don't want spam the log with this. |
421 | */ |
422 | return -ENOTSUPP; |
423 | } |
424 | |
425 | void snd_soc_component_setup_regmap(struct snd_soc_component *component) |
426 | { |
427 | int val_bytes = regmap_get_val_bytes(map: component->regmap); |
428 | |
429 | /* Errors are legitimate for non-integer byte multiples */ |
430 | if (val_bytes > 0) |
431 | component->val_bytes = val_bytes; |
432 | } |
433 | |
434 | #ifdef CONFIG_REGMAP |
435 | |
436 | /** |
437 | * snd_soc_component_init_regmap() - Initialize regmap instance for the |
438 | * component |
439 | * @component: The component for which to initialize the regmap instance |
440 | * @regmap: The regmap instance that should be used by the component |
441 | * |
442 | * This function allows deferred assignment of the regmap instance that is |
443 | * associated with the component. Only use this if the regmap instance is not |
444 | * yet ready when the component is registered. The function must also be called |
445 | * before the first IO attempt of the component. |
446 | */ |
447 | void snd_soc_component_init_regmap(struct snd_soc_component *component, |
448 | struct regmap *regmap) |
449 | { |
450 | component->regmap = regmap; |
451 | snd_soc_component_setup_regmap(component); |
452 | } |
453 | EXPORT_SYMBOL_GPL(snd_soc_component_init_regmap); |
454 | |
455 | /** |
456 | * snd_soc_component_exit_regmap() - De-initialize regmap instance for the |
457 | * component |
458 | * @component: The component for which to de-initialize the regmap instance |
459 | * |
460 | * Calls regmap_exit() on the regmap instance associated to the component and |
461 | * removes the regmap instance from the component. |
462 | * |
463 | * This function should only be used if snd_soc_component_init_regmap() was used |
464 | * to initialize the regmap instance. |
465 | */ |
466 | void snd_soc_component_exit_regmap(struct snd_soc_component *component) |
467 | { |
468 | regmap_exit(map: component->regmap); |
469 | component->regmap = NULL; |
470 | } |
471 | EXPORT_SYMBOL_GPL(snd_soc_component_exit_regmap); |
472 | |
473 | #endif |
474 | |
475 | int snd_soc_component_compr_open(struct snd_soc_component *component, |
476 | struct snd_compr_stream *cstream) |
477 | { |
478 | int ret = 0; |
479 | |
480 | if (component->driver->compress_ops && |
481 | component->driver->compress_ops->open) |
482 | ret = component->driver->compress_ops->open(component, cstream); |
483 | |
484 | /* mark substream if succeeded */ |
485 | if (ret == 0) |
486 | soc_component_mark_push(component, cstream, compr_open); |
487 | |
488 | return soc_component_ret(component, ret); |
489 | } |
490 | EXPORT_SYMBOL_GPL(snd_soc_component_compr_open); |
491 | |
492 | void snd_soc_component_compr_free(struct snd_soc_component *component, |
493 | struct snd_compr_stream *cstream, |
494 | int rollback) |
495 | { |
496 | if (rollback && !soc_component_mark_match(component, cstream, compr_open)) |
497 | return; |
498 | |
499 | if (component->driver->compress_ops && |
500 | component->driver->compress_ops->free) |
501 | component->driver->compress_ops->free(component, cstream); |
502 | |
503 | /* remove marked substream */ |
504 | soc_component_mark_pop(component, cstream, compr_open); |
505 | } |
506 | EXPORT_SYMBOL_GPL(snd_soc_component_compr_free); |
507 | |
508 | int snd_soc_component_compr_trigger(struct snd_compr_stream *cstream, int cmd) |
509 | { |
510 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; |
511 | struct snd_soc_component *component; |
512 | int i, ret; |
513 | |
514 | for_each_rtd_components(rtd, i, component) { |
515 | if (component->driver->compress_ops && |
516 | component->driver->compress_ops->trigger) { |
517 | ret = component->driver->compress_ops->trigger( |
518 | component, cstream, cmd); |
519 | if (ret < 0) |
520 | return soc_component_ret(component, ret); |
521 | } |
522 | } |
523 | |
524 | return 0; |
525 | } |
526 | EXPORT_SYMBOL_GPL(snd_soc_component_compr_trigger); |
527 | |
528 | int snd_soc_component_compr_set_params(struct snd_compr_stream *cstream, |
529 | struct snd_compr_params *params) |
530 | { |
531 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; |
532 | struct snd_soc_component *component; |
533 | int i, ret; |
534 | |
535 | for_each_rtd_components(rtd, i, component) { |
536 | if (component->driver->compress_ops && |
537 | component->driver->compress_ops->set_params) { |
538 | ret = component->driver->compress_ops->set_params( |
539 | component, cstream, params); |
540 | if (ret < 0) |
541 | return soc_component_ret(component, ret); |
542 | } |
543 | } |
544 | |
545 | return 0; |
546 | } |
547 | EXPORT_SYMBOL_GPL(snd_soc_component_compr_set_params); |
548 | |
549 | int snd_soc_component_compr_get_params(struct snd_compr_stream *cstream, |
550 | struct snd_codec *params) |
551 | { |
552 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; |
553 | struct snd_soc_component *component; |
554 | int i, ret; |
555 | |
556 | for_each_rtd_components(rtd, i, component) { |
557 | if (component->driver->compress_ops && |
558 | component->driver->compress_ops->get_params) { |
559 | ret = component->driver->compress_ops->get_params( |
560 | component, cstream, params); |
561 | return soc_component_ret(component, ret); |
562 | } |
563 | } |
564 | |
565 | return 0; |
566 | } |
567 | EXPORT_SYMBOL_GPL(snd_soc_component_compr_get_params); |
568 | |
569 | int snd_soc_component_compr_get_caps(struct snd_compr_stream *cstream, |
570 | struct snd_compr_caps *caps) |
571 | { |
572 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; |
573 | struct snd_soc_component *component; |
574 | int i, ret = 0; |
575 | |
576 | snd_soc_dpcm_mutex_lock(rtd); |
577 | |
578 | for_each_rtd_components(rtd, i, component) { |
579 | if (component->driver->compress_ops && |
580 | component->driver->compress_ops->get_caps) { |
581 | ret = component->driver->compress_ops->get_caps( |
582 | component, cstream, caps); |
583 | break; |
584 | } |
585 | } |
586 | |
587 | snd_soc_dpcm_mutex_unlock(rtd); |
588 | |
589 | return soc_component_ret(component, ret); |
590 | } |
591 | EXPORT_SYMBOL_GPL(snd_soc_component_compr_get_caps); |
592 | |
593 | int snd_soc_component_compr_get_codec_caps(struct snd_compr_stream *cstream, |
594 | struct snd_compr_codec_caps *codec) |
595 | { |
596 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; |
597 | struct snd_soc_component *component; |
598 | int i, ret = 0; |
599 | |
600 | snd_soc_dpcm_mutex_lock(rtd); |
601 | |
602 | for_each_rtd_components(rtd, i, component) { |
603 | if (component->driver->compress_ops && |
604 | component->driver->compress_ops->get_codec_caps) { |
605 | ret = component->driver->compress_ops->get_codec_caps( |
606 | component, cstream, codec); |
607 | break; |
608 | } |
609 | } |
610 | |
611 | snd_soc_dpcm_mutex_unlock(rtd); |
612 | |
613 | return soc_component_ret(component, ret); |
614 | } |
615 | EXPORT_SYMBOL_GPL(snd_soc_component_compr_get_codec_caps); |
616 | |
617 | int snd_soc_component_compr_ack(struct snd_compr_stream *cstream, size_t bytes) |
618 | { |
619 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; |
620 | struct snd_soc_component *component; |
621 | int i, ret; |
622 | |
623 | for_each_rtd_components(rtd, i, component) { |
624 | if (component->driver->compress_ops && |
625 | component->driver->compress_ops->ack) { |
626 | ret = component->driver->compress_ops->ack( |
627 | component, cstream, bytes); |
628 | if (ret < 0) |
629 | return soc_component_ret(component, ret); |
630 | } |
631 | } |
632 | |
633 | return 0; |
634 | } |
635 | EXPORT_SYMBOL_GPL(snd_soc_component_compr_ack); |
636 | |
637 | int snd_soc_component_compr_pointer(struct snd_compr_stream *cstream, |
638 | struct snd_compr_tstamp *tstamp) |
639 | { |
640 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; |
641 | struct snd_soc_component *component; |
642 | int i, ret; |
643 | |
644 | for_each_rtd_components(rtd, i, component) { |
645 | if (component->driver->compress_ops && |
646 | component->driver->compress_ops->pointer) { |
647 | ret = component->driver->compress_ops->pointer( |
648 | component, cstream, tstamp); |
649 | return soc_component_ret(component, ret); |
650 | } |
651 | } |
652 | |
653 | return 0; |
654 | } |
655 | EXPORT_SYMBOL_GPL(snd_soc_component_compr_pointer); |
656 | |
657 | int snd_soc_component_compr_copy(struct snd_compr_stream *cstream, |
658 | char __user *buf, size_t count) |
659 | { |
660 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; |
661 | struct snd_soc_component *component; |
662 | int i, ret = 0; |
663 | |
664 | snd_soc_dpcm_mutex_lock(rtd); |
665 | |
666 | for_each_rtd_components(rtd, i, component) { |
667 | if (component->driver->compress_ops && |
668 | component->driver->compress_ops->copy) { |
669 | ret = component->driver->compress_ops->copy( |
670 | component, cstream, buf, count); |
671 | break; |
672 | } |
673 | } |
674 | |
675 | snd_soc_dpcm_mutex_unlock(rtd); |
676 | |
677 | return soc_component_ret(component, ret); |
678 | } |
679 | EXPORT_SYMBOL_GPL(snd_soc_component_compr_copy); |
680 | |
681 | int snd_soc_component_compr_set_metadata(struct snd_compr_stream *cstream, |
682 | struct snd_compr_metadata *metadata) |
683 | { |
684 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; |
685 | struct snd_soc_component *component; |
686 | int i, ret; |
687 | |
688 | for_each_rtd_components(rtd, i, component) { |
689 | if (component->driver->compress_ops && |
690 | component->driver->compress_ops->set_metadata) { |
691 | ret = component->driver->compress_ops->set_metadata( |
692 | component, cstream, metadata); |
693 | if (ret < 0) |
694 | return soc_component_ret(component, ret); |
695 | } |
696 | } |
697 | |
698 | return 0; |
699 | } |
700 | EXPORT_SYMBOL_GPL(snd_soc_component_compr_set_metadata); |
701 | |
702 | int snd_soc_component_compr_get_metadata(struct snd_compr_stream *cstream, |
703 | struct snd_compr_metadata *metadata) |
704 | { |
705 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; |
706 | struct snd_soc_component *component; |
707 | int i, ret; |
708 | |
709 | for_each_rtd_components(rtd, i, component) { |
710 | if (component->driver->compress_ops && |
711 | component->driver->compress_ops->get_metadata) { |
712 | ret = component->driver->compress_ops->get_metadata( |
713 | component, cstream, metadata); |
714 | return soc_component_ret(component, ret); |
715 | } |
716 | } |
717 | |
718 | return 0; |
719 | } |
720 | EXPORT_SYMBOL_GPL(snd_soc_component_compr_get_metadata); |
721 | |
722 | static unsigned int soc_component_read_no_lock( |
723 | struct snd_soc_component *component, |
724 | unsigned int reg) |
725 | { |
726 | int ret; |
727 | unsigned int val = 0; |
728 | |
729 | if (component->regmap) |
730 | ret = regmap_read(map: component->regmap, reg, val: &val); |
731 | else if (component->driver->read) { |
732 | ret = 0; |
733 | val = component->driver->read(component, reg); |
734 | } |
735 | else |
736 | ret = -EIO; |
737 | |
738 | if (ret < 0) |
739 | return soc_component_ret_reg_rw(component, ret, reg); |
740 | |
741 | return val; |
742 | } |
743 | |
744 | /** |
745 | * snd_soc_component_read() - Read register value |
746 | * @component: Component to read from |
747 | * @reg: Register to read |
748 | * |
749 | * Return: read value |
750 | */ |
751 | unsigned int snd_soc_component_read(struct snd_soc_component *component, |
752 | unsigned int reg) |
753 | { |
754 | unsigned int val; |
755 | |
756 | mutex_lock(&component->io_mutex); |
757 | val = soc_component_read_no_lock(component, reg); |
758 | mutex_unlock(lock: &component->io_mutex); |
759 | |
760 | return val; |
761 | } |
762 | EXPORT_SYMBOL_GPL(snd_soc_component_read); |
763 | |
764 | static int soc_component_write_no_lock( |
765 | struct snd_soc_component *component, |
766 | unsigned int reg, unsigned int val) |
767 | { |
768 | int ret = -EIO; |
769 | |
770 | if (component->regmap) |
771 | ret = regmap_write(map: component->regmap, reg, val); |
772 | else if (component->driver->write) |
773 | ret = component->driver->write(component, reg, val); |
774 | |
775 | return soc_component_ret_reg_rw(component, ret, reg); |
776 | } |
777 | |
778 | /** |
779 | * snd_soc_component_write() - Write register value |
780 | * @component: Component to write to |
781 | * @reg: Register to write |
782 | * @val: Value to write to the register |
783 | * |
784 | * Return: 0 on success, a negative error code otherwise. |
785 | */ |
786 | int snd_soc_component_write(struct snd_soc_component *component, |
787 | unsigned int reg, unsigned int val) |
788 | { |
789 | int ret; |
790 | |
791 | mutex_lock(&component->io_mutex); |
792 | ret = soc_component_write_no_lock(component, reg, val); |
793 | mutex_unlock(lock: &component->io_mutex); |
794 | |
795 | return ret; |
796 | } |
797 | EXPORT_SYMBOL_GPL(snd_soc_component_write); |
798 | |
799 | static int snd_soc_component_update_bits_legacy( |
800 | struct snd_soc_component *component, unsigned int reg, |
801 | unsigned int mask, unsigned int val, bool *change) |
802 | { |
803 | unsigned int old, new; |
804 | int ret = 0; |
805 | |
806 | mutex_lock(&component->io_mutex); |
807 | |
808 | old = soc_component_read_no_lock(component, reg); |
809 | |
810 | new = (old & ~mask) | (val & mask); |
811 | *change = old != new; |
812 | if (*change) |
813 | ret = soc_component_write_no_lock(component, reg, val: new); |
814 | |
815 | mutex_unlock(lock: &component->io_mutex); |
816 | |
817 | return soc_component_ret_reg_rw(component, ret, reg); |
818 | } |
819 | |
820 | /** |
821 | * snd_soc_component_update_bits() - Perform read/modify/write cycle |
822 | * @component: Component to update |
823 | * @reg: Register to update |
824 | * @mask: Mask that specifies which bits to update |
825 | * @val: New value for the bits specified by mask |
826 | * |
827 | * Return: 1 if the operation was successful and the value of the register |
828 | * changed, 0 if the operation was successful, but the value did not change. |
829 | * Returns a negative error code otherwise. |
830 | */ |
831 | int snd_soc_component_update_bits(struct snd_soc_component *component, |
832 | unsigned int reg, unsigned int mask, unsigned int val) |
833 | { |
834 | bool change; |
835 | int ret; |
836 | |
837 | if (component->regmap) |
838 | ret = regmap_update_bits_check(map: component->regmap, reg, mask, |
839 | val, change: &change); |
840 | else |
841 | ret = snd_soc_component_update_bits_legacy(component, reg, |
842 | mask, val, change: &change); |
843 | |
844 | if (ret < 0) |
845 | return soc_component_ret_reg_rw(component, ret, reg); |
846 | return change; |
847 | } |
848 | EXPORT_SYMBOL_GPL(snd_soc_component_update_bits); |
849 | |
850 | /** |
851 | * snd_soc_component_update_bits_async() - Perform asynchronous |
852 | * read/modify/write cycle |
853 | * @component: Component to update |
854 | * @reg: Register to update |
855 | * @mask: Mask that specifies which bits to update |
856 | * @val: New value for the bits specified by mask |
857 | * |
858 | * This function is similar to snd_soc_component_update_bits(), but the update |
859 | * operation is scheduled asynchronously. This means it may not be completed |
860 | * when the function returns. To make sure that all scheduled updates have been |
861 | * completed snd_soc_component_async_complete() must be called. |
862 | * |
863 | * Return: 1 if the operation was successful and the value of the register |
864 | * changed, 0 if the operation was successful, but the value did not change. |
865 | * Returns a negative error code otherwise. |
866 | */ |
867 | int snd_soc_component_update_bits_async(struct snd_soc_component *component, |
868 | unsigned int reg, unsigned int mask, unsigned int val) |
869 | { |
870 | bool change; |
871 | int ret; |
872 | |
873 | if (component->regmap) |
874 | ret = regmap_update_bits_check_async(map: component->regmap, reg, |
875 | mask, val, change: &change); |
876 | else |
877 | ret = snd_soc_component_update_bits_legacy(component, reg, |
878 | mask, val, change: &change); |
879 | |
880 | if (ret < 0) |
881 | return soc_component_ret_reg_rw(component, ret, reg); |
882 | return change; |
883 | } |
884 | EXPORT_SYMBOL_GPL(snd_soc_component_update_bits_async); |
885 | |
886 | /** |
887 | * snd_soc_component_read_field() - Read register field value |
888 | * @component: Component to read from |
889 | * @reg: Register to read |
890 | * @mask: mask of the register field |
891 | * |
892 | * Return: read value of register field. |
893 | */ |
894 | unsigned int snd_soc_component_read_field(struct snd_soc_component *component, |
895 | unsigned int reg, unsigned int mask) |
896 | { |
897 | unsigned int val; |
898 | |
899 | val = snd_soc_component_read(component, reg); |
900 | |
901 | val = (val & mask) >> soc_component_field_shift(component, mask); |
902 | |
903 | return val; |
904 | } |
905 | EXPORT_SYMBOL_GPL(snd_soc_component_read_field); |
906 | |
907 | /** |
908 | * snd_soc_component_write_field() - write to register field |
909 | * @component: Component to write to |
910 | * @reg: Register to write |
911 | * @mask: mask of the register field to update |
912 | * @val: value of the field to write |
913 | * |
914 | * Return: 1 for change, otherwise 0. |
915 | */ |
916 | int snd_soc_component_write_field(struct snd_soc_component *component, |
917 | unsigned int reg, unsigned int mask, |
918 | unsigned int val) |
919 | { |
920 | |
921 | val = (val << soc_component_field_shift(component, mask)) & mask; |
922 | |
923 | return snd_soc_component_update_bits(component, reg, mask, val); |
924 | } |
925 | EXPORT_SYMBOL_GPL(snd_soc_component_write_field); |
926 | |
927 | /** |
928 | * snd_soc_component_async_complete() - Ensure asynchronous I/O has completed |
929 | * @component: Component for which to wait |
930 | * |
931 | * This function blocks until all asynchronous I/O which has previously been |
932 | * scheduled using snd_soc_component_update_bits_async() has completed. |
933 | */ |
934 | void snd_soc_component_async_complete(struct snd_soc_component *component) |
935 | { |
936 | if (component->regmap) |
937 | regmap_async_complete(map: component->regmap); |
938 | } |
939 | EXPORT_SYMBOL_GPL(snd_soc_component_async_complete); |
940 | |
941 | /** |
942 | * snd_soc_component_test_bits - Test register for change |
943 | * @component: component |
944 | * @reg: Register to test |
945 | * @mask: Mask that specifies which bits to test |
946 | * @value: Value to test against |
947 | * |
948 | * Tests a register with a new value and checks if the new value is |
949 | * different from the old value. |
950 | * |
951 | * Return: 1 for change, otherwise 0. |
952 | */ |
953 | int snd_soc_component_test_bits(struct snd_soc_component *component, |
954 | unsigned int reg, unsigned int mask, unsigned int value) |
955 | { |
956 | unsigned int old, new; |
957 | |
958 | old = snd_soc_component_read(component, reg); |
959 | new = (old & ~mask) | value; |
960 | return old != new; |
961 | } |
962 | EXPORT_SYMBOL_GPL(snd_soc_component_test_bits); |
963 | |
964 | int snd_soc_pcm_component_pointer(struct snd_pcm_substream *substream) |
965 | { |
966 | struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); |
967 | struct snd_soc_component *component; |
968 | int i; |
969 | |
970 | /* FIXME: use 1st pointer */ |
971 | for_each_rtd_components(rtd, i, component) |
972 | if (component->driver->pointer) |
973 | return component->driver->pointer(component, substream); |
974 | |
975 | return 0; |
976 | } |
977 | |
978 | static bool snd_soc_component_is_codec_on_rtd(struct snd_soc_pcm_runtime *rtd, |
979 | struct snd_soc_component *component) |
980 | { |
981 | struct snd_soc_dai *dai; |
982 | int i; |
983 | |
984 | for_each_rtd_codec_dais(rtd, i, dai) { |
985 | if (dai->component == component) |
986 | return true; |
987 | } |
988 | |
989 | return false; |
990 | } |
991 | |
992 | void snd_soc_pcm_component_delay(struct snd_pcm_substream *substream, |
993 | snd_pcm_sframes_t *cpu_delay, |
994 | snd_pcm_sframes_t *codec_delay) |
995 | { |
996 | struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); |
997 | struct snd_soc_component *component; |
998 | snd_pcm_sframes_t delay; |
999 | int i; |
1000 | |
1001 | /* |
1002 | * We're looking for the delay through the full audio path so it needs to |
1003 | * be the maximum of the Components doing transmit and the maximum of the |
1004 | * Components doing receive (ie, all CPUs and all CODECs) rather than |
1005 | * just the maximum of all Components. |
1006 | */ |
1007 | for_each_rtd_components(rtd, i, component) { |
1008 | if (!component->driver->delay) |
1009 | continue; |
1010 | |
1011 | delay = component->driver->delay(component, substream); |
1012 | |
1013 | if (snd_soc_component_is_codec_on_rtd(rtd, component)) |
1014 | *codec_delay = max(*codec_delay, delay); |
1015 | else |
1016 | *cpu_delay = max(*cpu_delay, delay); |
1017 | } |
1018 | } |
1019 | |
1020 | int snd_soc_pcm_component_ioctl(struct snd_pcm_substream *substream, |
1021 | unsigned int cmd, void *arg) |
1022 | { |
1023 | struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); |
1024 | struct snd_soc_component *component; |
1025 | int i; |
1026 | |
1027 | /* FIXME: use 1st ioctl */ |
1028 | for_each_rtd_components(rtd, i, component) |
1029 | if (component->driver->ioctl) |
1030 | return soc_component_ret( |
1031 | component, |
1032 | component->driver->ioctl(component, |
1033 | substream, cmd, arg)); |
1034 | |
1035 | return snd_pcm_lib_ioctl(substream, cmd, arg); |
1036 | } |
1037 | |
1038 | int snd_soc_pcm_component_sync_stop(struct snd_pcm_substream *substream) |
1039 | { |
1040 | struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); |
1041 | struct snd_soc_component *component; |
1042 | int i, ret; |
1043 | |
1044 | for_each_rtd_components(rtd, i, component) { |
1045 | if (component->driver->sync_stop) { |
1046 | ret = component->driver->sync_stop(component, |
1047 | substream); |
1048 | if (ret < 0) |
1049 | return soc_component_ret(component, ret); |
1050 | } |
1051 | } |
1052 | |
1053 | return 0; |
1054 | } |
1055 | |
1056 | int snd_soc_pcm_component_copy(struct snd_pcm_substream *substream, |
1057 | int channel, unsigned long pos, |
1058 | struct iov_iter *iter, unsigned long bytes) |
1059 | { |
1060 | struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); |
1061 | struct snd_soc_component *component; |
1062 | int i; |
1063 | |
1064 | /* FIXME. it returns 1st copy now */ |
1065 | for_each_rtd_components(rtd, i, component) |
1066 | if (component->driver->copy) |
1067 | return soc_component_ret(component, |
1068 | component->driver->copy(component, substream, |
1069 | channel, pos, iter, bytes)); |
1070 | |
1071 | return -EINVAL; |
1072 | } |
1073 | |
1074 | struct page *snd_soc_pcm_component_page(struct snd_pcm_substream *substream, |
1075 | unsigned long offset) |
1076 | { |
1077 | struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); |
1078 | struct snd_soc_component *component; |
1079 | struct page *page; |
1080 | int i; |
1081 | |
1082 | /* FIXME. it returns 1st page now */ |
1083 | for_each_rtd_components(rtd, i, component) { |
1084 | if (component->driver->page) { |
1085 | page = component->driver->page(component, |
1086 | substream, offset); |
1087 | if (page) |
1088 | return page; |
1089 | } |
1090 | } |
1091 | |
1092 | return NULL; |
1093 | } |
1094 | |
1095 | int snd_soc_pcm_component_mmap(struct snd_pcm_substream *substream, |
1096 | struct vm_area_struct *vma) |
1097 | { |
1098 | struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); |
1099 | struct snd_soc_component *component; |
1100 | int i; |
1101 | |
1102 | /* FIXME. it returns 1st mmap now */ |
1103 | for_each_rtd_components(rtd, i, component) |
1104 | if (component->driver->mmap) |
1105 | return soc_component_ret( |
1106 | component, |
1107 | component->driver->mmap(component, |
1108 | substream, vma)); |
1109 | |
1110 | return -EINVAL; |
1111 | } |
1112 | |
1113 | int snd_soc_pcm_component_new(struct snd_soc_pcm_runtime *rtd) |
1114 | { |
1115 | struct snd_soc_component *component; |
1116 | int ret; |
1117 | int i; |
1118 | |
1119 | for_each_rtd_components(rtd, i, component) { |
1120 | if (component->driver->pcm_construct) { |
1121 | ret = component->driver->pcm_construct(component, rtd); |
1122 | if (ret < 0) |
1123 | return soc_component_ret(component, ret); |
1124 | } |
1125 | } |
1126 | |
1127 | return 0; |
1128 | } |
1129 | |
1130 | void snd_soc_pcm_component_free(struct snd_soc_pcm_runtime *rtd) |
1131 | { |
1132 | struct snd_soc_component *component; |
1133 | int i; |
1134 | |
1135 | if (!rtd->pcm) |
1136 | return; |
1137 | |
1138 | for_each_rtd_components(rtd, i, component) |
1139 | if (component->driver->pcm_destruct) |
1140 | component->driver->pcm_destruct(component, rtd->pcm); |
1141 | } |
1142 | |
1143 | int snd_soc_pcm_component_prepare(struct snd_pcm_substream *substream) |
1144 | { |
1145 | struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); |
1146 | struct snd_soc_component *component; |
1147 | int i, ret; |
1148 | |
1149 | for_each_rtd_components(rtd, i, component) { |
1150 | if (component->driver->prepare) { |
1151 | ret = component->driver->prepare(component, substream); |
1152 | if (ret < 0) |
1153 | return soc_component_ret(component, ret); |
1154 | } |
1155 | } |
1156 | |
1157 | return 0; |
1158 | } |
1159 | |
1160 | int snd_soc_pcm_component_hw_params(struct snd_pcm_substream *substream, |
1161 | struct snd_pcm_hw_params *params) |
1162 | { |
1163 | struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); |
1164 | struct snd_soc_component *component; |
1165 | int i, ret; |
1166 | |
1167 | for_each_rtd_components(rtd, i, component) { |
1168 | if (component->driver->hw_params) { |
1169 | ret = component->driver->hw_params(component, |
1170 | substream, params); |
1171 | if (ret < 0) |
1172 | return soc_component_ret(component, ret); |
1173 | } |
1174 | /* mark substream if succeeded */ |
1175 | soc_component_mark_push(component, substream, hw_params); |
1176 | } |
1177 | |
1178 | return 0; |
1179 | } |
1180 | |
1181 | void snd_soc_pcm_component_hw_free(struct snd_pcm_substream *substream, |
1182 | int rollback) |
1183 | { |
1184 | struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); |
1185 | struct snd_soc_component *component; |
1186 | int i, ret; |
1187 | |
1188 | for_each_rtd_components(rtd, i, component) { |
1189 | if (rollback && !soc_component_mark_match(component, substream, hw_params)) |
1190 | continue; |
1191 | |
1192 | if (component->driver->hw_free) { |
1193 | ret = component->driver->hw_free(component, substream); |
1194 | if (ret < 0) |
1195 | soc_component_ret(component, ret); |
1196 | } |
1197 | |
1198 | /* remove marked substream */ |
1199 | soc_component_mark_pop(component, substream, hw_params); |
1200 | } |
1201 | } |
1202 | |
1203 | static int soc_component_trigger(struct snd_soc_component *component, |
1204 | struct snd_pcm_substream *substream, |
1205 | int cmd) |
1206 | { |
1207 | int ret = 0; |
1208 | |
1209 | if (component->driver->trigger) |
1210 | ret = component->driver->trigger(component, substream, cmd); |
1211 | |
1212 | return soc_component_ret(component, ret); |
1213 | } |
1214 | |
1215 | int snd_soc_pcm_component_trigger(struct snd_pcm_substream *substream, |
1216 | int cmd, int rollback) |
1217 | { |
1218 | struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); |
1219 | struct snd_soc_component *component; |
1220 | int i, r, ret = 0; |
1221 | |
1222 | switch (cmd) { |
1223 | case SNDRV_PCM_TRIGGER_START: |
1224 | case SNDRV_PCM_TRIGGER_RESUME: |
1225 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
1226 | for_each_rtd_components(rtd, i, component) { |
1227 | ret = soc_component_trigger(component, substream, cmd); |
1228 | if (ret < 0) |
1229 | break; |
1230 | soc_component_mark_push(component, substream, trigger); |
1231 | } |
1232 | break; |
1233 | case SNDRV_PCM_TRIGGER_STOP: |
1234 | case SNDRV_PCM_TRIGGER_SUSPEND: |
1235 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
1236 | for_each_rtd_components(rtd, i, component) { |
1237 | if (rollback && !soc_component_mark_match(component, substream, trigger)) |
1238 | continue; |
1239 | |
1240 | r = soc_component_trigger(component, substream, cmd); |
1241 | if (r < 0) |
1242 | ret = r; /* use last ret */ |
1243 | soc_component_mark_pop(component, substream, trigger); |
1244 | } |
1245 | } |
1246 | |
1247 | return ret; |
1248 | } |
1249 | |
1250 | int snd_soc_pcm_component_pm_runtime_get(struct snd_soc_pcm_runtime *rtd, |
1251 | void *stream) |
1252 | { |
1253 | struct snd_soc_component *component; |
1254 | int i; |
1255 | |
1256 | for_each_rtd_components(rtd, i, component) { |
1257 | int ret = pm_runtime_get_sync(dev: component->dev); |
1258 | if (ret < 0 && ret != -EACCES) { |
1259 | pm_runtime_put_noidle(dev: component->dev); |
1260 | return soc_component_ret(component, ret); |
1261 | } |
1262 | /* mark stream if succeeded */ |
1263 | soc_component_mark_push(component, stream, pm); |
1264 | } |
1265 | |
1266 | return 0; |
1267 | } |
1268 | |
1269 | void snd_soc_pcm_component_pm_runtime_put(struct snd_soc_pcm_runtime *rtd, |
1270 | void *stream, int rollback) |
1271 | { |
1272 | struct snd_soc_component *component; |
1273 | int i; |
1274 | |
1275 | for_each_rtd_components(rtd, i, component) { |
1276 | if (rollback && !soc_component_mark_match(component, stream, pm)) |
1277 | continue; |
1278 | |
1279 | pm_runtime_mark_last_busy(dev: component->dev); |
1280 | pm_runtime_put_autosuspend(dev: component->dev); |
1281 | |
1282 | /* remove marked stream */ |
1283 | soc_component_mark_pop(component, stream, pm); |
1284 | } |
1285 | } |
1286 | |
1287 | int snd_soc_pcm_component_ack(struct snd_pcm_substream *substream) |
1288 | { |
1289 | struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); |
1290 | struct snd_soc_component *component; |
1291 | int i; |
1292 | |
1293 | /* FIXME: use 1st pointer */ |
1294 | for_each_rtd_components(rtd, i, component) |
1295 | if (component->driver->ack) |
1296 | return component->driver->ack(component, substream); |
1297 | |
1298 | return 0; |
1299 | } |
1300 | |