Merge tag 'linux-watchdog-6.3-rc1' of git://www.linux-watchdog.org/linux-watchdog
[platform/kernel/linux-rpi.git] / sound / soc / sof / sof-audio.c
1 // SPDX-License-Identifier: (GPL-2.0-only 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) 2019 Intel Corporation. All rights reserved.
7 //
8 // Author: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
9 //
10
11 #include <linux/bitfield.h>
12 #include <trace/events/sof.h>
13 #include "sof-audio.h"
14 #include "sof-of-dev.h"
15 #include "ops.h"
16
17 static void sof_reset_route_setup_status(struct snd_sof_dev *sdev, struct snd_sof_widget *widget)
18 {
19         const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
20         struct snd_sof_route *sroute;
21
22         list_for_each_entry(sroute, &sdev->route_list, list)
23                 if (sroute->src_widget == widget || sroute->sink_widget == widget) {
24                         if (sroute->setup && tplg_ops && tplg_ops->route_free)
25                                 tplg_ops->route_free(sdev, sroute);
26
27                         sroute->setup = false;
28                 }
29 }
30
31 static int sof_widget_free_unlocked(struct snd_sof_dev *sdev,
32                                     struct snd_sof_widget *swidget)
33 {
34         const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
35         struct snd_sof_widget *pipe_widget;
36         int err = 0;
37         int ret;
38
39         if (!swidget->private)
40                 return 0;
41
42         trace_sof_widget_free(swidget);
43
44         /* only free when use_count is 0 */
45         if (--swidget->use_count)
46                 return 0;
47
48         pipe_widget = swidget->spipe->pipe_widget;
49
50         /* reset route setup status for all routes that contain this widget */
51         sof_reset_route_setup_status(sdev, swidget);
52
53         /* continue to disable core even if IPC fails */
54         if (tplg_ops && tplg_ops->widget_free)
55                 err = tplg_ops->widget_free(sdev, swidget);
56
57         /*
58          * disable widget core. continue to route setup status and complete flag
59          * even if this fails and return the appropriate error
60          */
61         ret = snd_sof_dsp_core_put(sdev, swidget->core);
62         if (ret < 0) {
63                 dev_err(sdev->dev, "error: failed to disable target core: %d for widget %s\n",
64                         swidget->core, swidget->widget->name);
65                 if (!err)
66                         err = ret;
67         }
68
69         /*
70          * free the scheduler widget (same as pipe_widget) associated with the current swidget.
71          * skip for static pipelines
72          */
73         if (swidget->dynamic_pipeline_widget && swidget->id != snd_soc_dapm_scheduler) {
74                 ret = sof_widget_free_unlocked(sdev, pipe_widget);
75                 if (ret < 0 && !err)
76                         err = ret;
77         }
78
79         /* clear pipeline complete */
80         if (swidget->id == snd_soc_dapm_scheduler)
81                 swidget->spipe->complete = 0;
82
83         if (!err)
84                 dev_dbg(sdev->dev, "widget %s freed\n", swidget->widget->name);
85
86         return err;
87 }
88
89 int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
90 {
91         int ret;
92
93         mutex_lock(&swidget->setup_mutex);
94         ret = sof_widget_free_unlocked(sdev, swidget);
95         mutex_unlock(&swidget->setup_mutex);
96
97         return ret;
98 }
99 EXPORT_SYMBOL(sof_widget_free);
100
101 static int sof_widget_setup_unlocked(struct snd_sof_dev *sdev,
102                                      struct snd_sof_widget *swidget)
103 {
104         const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
105         bool use_count_decremented = false;
106         int ret;
107
108         /* skip if there is no private data */
109         if (!swidget->private)
110                 return 0;
111
112         trace_sof_widget_setup(swidget);
113
114         /* widget already set up */
115         if (++swidget->use_count > 1)
116                 return 0;
117
118         /*
119          * The scheduler widget for a pipeline is not part of the connected DAPM
120          * widget list and it needs to be set up before the widgets in the pipeline
121          * are set up. The use_count for the scheduler widget is incremented for every
122          * widget in a given pipeline to ensure that it is freed only after the last
123          * widget in the pipeline is freed. Skip setting up scheduler widget for static pipelines.
124          */
125         if (swidget->dynamic_pipeline_widget && swidget->id != snd_soc_dapm_scheduler) {
126                 if (!swidget->spipe || !swidget->spipe->pipe_widget) {
127                         dev_err(sdev->dev, "No pipeline set for %s\n", swidget->widget->name);
128                         ret = -EINVAL;
129                         goto use_count_dec;
130                 }
131
132                 ret = sof_widget_setup_unlocked(sdev, swidget->spipe->pipe_widget);
133                 if (ret < 0)
134                         goto use_count_dec;
135         }
136
137         /* enable widget core */
138         ret = snd_sof_dsp_core_get(sdev, swidget->core);
139         if (ret < 0) {
140                 dev_err(sdev->dev, "error: failed to enable target core for widget %s\n",
141                         swidget->widget->name);
142                 goto pipe_widget_free;
143         }
144
145         /* setup widget in the DSP */
146         if (tplg_ops && tplg_ops->widget_setup) {
147                 ret = tplg_ops->widget_setup(sdev, swidget);
148                 if (ret < 0)
149                         goto core_put;
150         }
151
152         /* send config for DAI components */
153         if (WIDGET_IS_DAI(swidget->id)) {
154                 unsigned int flags = SOF_DAI_CONFIG_FLAGS_NONE;
155
156                 if (tplg_ops && tplg_ops->dai_config) {
157                         ret = tplg_ops->dai_config(sdev, swidget, flags, NULL);
158                         if (ret < 0)
159                                 goto widget_free;
160                 }
161         }
162
163         /* restore kcontrols for widget */
164         if (tplg_ops && tplg_ops->control && tplg_ops->control->widget_kcontrol_setup) {
165                 ret = tplg_ops->control->widget_kcontrol_setup(sdev, swidget);
166                 if (ret < 0)
167                         goto widget_free;
168         }
169
170         dev_dbg(sdev->dev, "widget %s setup complete\n", swidget->widget->name);
171
172         return 0;
173
174 widget_free:
175         /* widget use_count and core ref_count will both be decremented by sof_widget_free() */
176         sof_widget_free_unlocked(sdev, swidget);
177         use_count_decremented = true;
178 core_put:
179         snd_sof_dsp_core_put(sdev, swidget->core);
180 pipe_widget_free:
181         if (swidget->id != snd_soc_dapm_scheduler)
182                 sof_widget_free_unlocked(sdev, swidget->spipe->pipe_widget);
183 use_count_dec:
184         if (!use_count_decremented)
185                 swidget->use_count--;
186
187         return ret;
188 }
189
190 int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
191 {
192         int ret;
193
194         mutex_lock(&swidget->setup_mutex);
195         ret = sof_widget_setup_unlocked(sdev, swidget);
196         mutex_unlock(&swidget->setup_mutex);
197
198         return ret;
199 }
200 EXPORT_SYMBOL(sof_widget_setup);
201
202 int sof_route_setup(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *wsource,
203                     struct snd_soc_dapm_widget *wsink)
204 {
205         const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
206         struct snd_sof_widget *src_widget = wsource->dobj.private;
207         struct snd_sof_widget *sink_widget = wsink->dobj.private;
208         struct snd_sof_route *sroute;
209         bool route_found = false;
210
211         /* ignore routes involving virtual widgets in topology */
212         switch (src_widget->id) {
213         case snd_soc_dapm_out_drv:
214         case snd_soc_dapm_output:
215         case snd_soc_dapm_input:
216                 return 0;
217         default:
218                 break;
219         }
220
221         switch (sink_widget->id) {
222         case snd_soc_dapm_out_drv:
223         case snd_soc_dapm_output:
224         case snd_soc_dapm_input:
225                 return 0;
226         default:
227                 break;
228         }
229
230         /* find route matching source and sink widgets */
231         list_for_each_entry(sroute, &sdev->route_list, list)
232                 if (sroute->src_widget == src_widget && sroute->sink_widget == sink_widget) {
233                         route_found = true;
234                         break;
235                 }
236
237         if (!route_found) {
238                 dev_err(sdev->dev, "error: cannot find SOF route for source %s -> %s sink\n",
239                         wsource->name, wsink->name);
240                 return -EINVAL;
241         }
242
243         /* nothing to do if route is already set up */
244         if (sroute->setup)
245                 return 0;
246
247         if (tplg_ops && tplg_ops->route_setup) {
248                 int ret = tplg_ops->route_setup(sdev, sroute);
249
250                 if (ret < 0)
251                         return ret;
252         }
253
254         sroute->setup = true;
255         return 0;
256 }
257
258 static int sof_setup_pipeline_connections(struct snd_sof_dev *sdev,
259                                           struct snd_soc_dapm_widget_list *list, int dir)
260 {
261         struct snd_soc_dapm_widget *widget;
262         struct snd_soc_dapm_path *p;
263         int ret;
264         int i;
265
266         /*
267          * Set up connections between widgets in the sink/source paths based on direction.
268          * Some non-SOF widgets exist in topology either for compatibility or for the
269          * purpose of connecting a pipeline from a host to a DAI in order to receive the DAPM
270          * events. But they are not handled by the firmware. So ignore them.
271          */
272         if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
273                 for_each_dapm_widgets(list, i, widget) {
274                         if (!widget->dobj.private)
275                                 continue;
276
277                         snd_soc_dapm_widget_for_each_sink_path(widget, p) {
278                                 if (!widget_in_list(list, p->sink))
279                                         continue;
280
281                                 if (p->sink->dobj.private) {
282                                         ret = sof_route_setup(sdev, widget, p->sink);
283                                         if (ret < 0)
284                                                 return ret;
285                                 }
286                         }
287                 }
288         } else {
289                 for_each_dapm_widgets(list, i, widget) {
290                         if (!widget->dobj.private)
291                                 continue;
292
293                         snd_soc_dapm_widget_for_each_source_path(widget, p) {
294                                 if (!widget_in_list(list, p->source))
295                                         continue;
296
297                                 if (p->source->dobj.private) {
298                                         ret = sof_route_setup(sdev, p->source, widget);
299                                         if (ret < 0)
300                                                 return ret;
301                                 }
302                         }
303                 }
304         }
305
306         return 0;
307 }
308
309 static void
310 sof_unprepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget,
311                               struct snd_soc_dapm_widget_list *list)
312 {
313         const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
314         struct snd_sof_widget *swidget = widget->dobj.private;
315         const struct sof_ipc_tplg_widget_ops *widget_ops;
316         struct snd_soc_dapm_path *p;
317
318         /* skip if the widget is in use or if it is already unprepared */
319         if (!swidget || !swidget->prepared || swidget->use_count > 0)
320                 goto sink_unprepare;
321
322         widget_ops = tplg_ops ? tplg_ops->widget : NULL;
323         if (widget_ops && widget_ops[widget->id].ipc_unprepare)
324                 /* unprepare the source widget */
325                 widget_ops[widget->id].ipc_unprepare(swidget);
326
327         swidget->prepared = false;
328
329 sink_unprepare:
330         /* unprepare all widgets in the sink paths */
331         snd_soc_dapm_widget_for_each_sink_path(widget, p) {
332                 if (!widget_in_list(list, p->sink))
333                         continue;
334                 if (!p->walking && p->sink->dobj.private) {
335                         p->walking = true;
336                         sof_unprepare_widgets_in_path(sdev, p->sink, list);
337                         p->walking = false;
338                 }
339         }
340 }
341
342 static int
343 sof_prepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget,
344                             struct snd_pcm_hw_params *fe_params,
345                             struct snd_sof_platform_stream_params *platform_params,
346                             struct snd_pcm_hw_params *pipeline_params, int dir,
347                             struct snd_soc_dapm_widget_list *list)
348 {
349         const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
350         struct snd_sof_widget *swidget = widget->dobj.private;
351         const struct sof_ipc_tplg_widget_ops *widget_ops;
352         struct snd_soc_dapm_path *p;
353         int ret;
354
355         widget_ops = tplg_ops ? tplg_ops->widget : NULL;
356         if (!widget_ops)
357                 return 0;
358
359         if (!swidget || !widget_ops[widget->id].ipc_prepare || swidget->prepared)
360                 goto sink_prepare;
361
362         /* prepare the source widget */
363         ret = widget_ops[widget->id].ipc_prepare(swidget, fe_params, platform_params,
364                                              pipeline_params, dir);
365         if (ret < 0) {
366                 dev_err(sdev->dev, "failed to prepare widget %s\n", widget->name);
367                 return ret;
368         }
369
370         swidget->prepared = true;
371
372 sink_prepare:
373         /* prepare all widgets in the sink paths */
374         snd_soc_dapm_widget_for_each_sink_path(widget, p) {
375                 if (!widget_in_list(list, p->sink))
376                         continue;
377                 if (!p->walking && p->sink->dobj.private) {
378                         p->walking = true;
379                         ret = sof_prepare_widgets_in_path(sdev, p->sink,  fe_params,
380                                                           platform_params, pipeline_params, dir,
381                                                           list);
382                         p->walking = false;
383                         if (ret < 0) {
384                                 /* unprepare the source widget */
385                                 if (widget_ops[widget->id].ipc_unprepare &&
386                                     swidget && swidget->prepared) {
387                                         widget_ops[widget->id].ipc_unprepare(swidget);
388                                         swidget->prepared = false;
389                                 }
390                                 return ret;
391                         }
392                 }
393         }
394
395         return 0;
396 }
397
398 /*
399  * free all widgets in the sink path starting from the source widget
400  * (DAI type for capture, AIF type for playback)
401  */
402 static int sof_free_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget,
403                                     int dir, struct snd_sof_pcm *spcm)
404 {
405         struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list;
406         struct snd_soc_dapm_path *p;
407         int err;
408         int ret = 0;
409
410         if (widget->dobj.private) {
411                 err = sof_widget_free(sdev, widget->dobj.private);
412                 if (err < 0)
413                         ret = err;
414         }
415
416         /* free all widgets in the sink paths even in case of error to keep use counts balanced */
417         snd_soc_dapm_widget_for_each_sink_path(widget, p) {
418                 if (!p->walking) {
419                         if (!widget_in_list(list, p->sink))
420                                 continue;
421
422                         p->walking = true;
423
424                         err = sof_free_widgets_in_path(sdev, p->sink, dir, spcm);
425                         if (err < 0)
426                                 ret = err;
427                         p->walking = false;
428                 }
429         }
430
431         return ret;
432 }
433
434 /*
435  * set up all widgets in the sink path starting from the source widget
436  * (DAI type for capture, AIF type for playback).
437  * The error path in this function ensures that all successfully set up widgets getting freed.
438  */
439 static int sof_set_up_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget,
440                                       int dir, struct snd_sof_pcm *spcm)
441 {
442         struct snd_sof_pcm_stream_pipeline_list *pipeline_list = &spcm->stream[dir].pipeline_list;
443         struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list;
444         struct snd_sof_widget *swidget = widget->dobj.private;
445         struct snd_sof_pipeline *spipe;
446         struct snd_soc_dapm_path *p;
447         int ret;
448
449         if (swidget) {
450                 int i;
451
452                 ret = sof_widget_setup(sdev, widget->dobj.private);
453                 if (ret < 0)
454                         return ret;
455
456                 /* skip populating the pipe_widgets array if it is NULL */
457                 if (!pipeline_list->pipelines)
458                         goto sink_setup;
459
460                 /*
461                  * Add the widget's pipe_widget to the list of pipelines to be triggered if not
462                  * already in the list. This will result in the pipelines getting added in the
463                  * order source to sink.
464                  */
465                 for (i = 0; i < pipeline_list->count; i++) {
466                         spipe = pipeline_list->pipelines[i];
467                         if (spipe == swidget->spipe)
468                                 break;
469                 }
470
471                 if (i == pipeline_list->count) {
472                         pipeline_list->count++;
473                         pipeline_list->pipelines[i] = swidget->spipe;
474                 }
475         }
476
477 sink_setup:
478         snd_soc_dapm_widget_for_each_sink_path(widget, p) {
479                 if (!p->walking) {
480                         if (!widget_in_list(list, p->sink))
481                                 continue;
482
483                         p->walking = true;
484
485                         ret = sof_set_up_widgets_in_path(sdev, p->sink, dir, spcm);
486                         p->walking = false;
487                         if (ret < 0) {
488                                 if (swidget)
489                                         sof_widget_free(sdev, swidget);
490                                 return ret;
491                         }
492                 }
493         }
494
495         return 0;
496 }
497
498 static int
499 sof_walk_widgets_in_order(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm,
500                           struct snd_pcm_hw_params *fe_params,
501                           struct snd_sof_platform_stream_params *platform_params, int dir,
502                           enum sof_widget_op op)
503 {
504         struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list;
505         struct snd_soc_dapm_widget *widget;
506         char *str;
507         int ret = 0;
508         int i;
509
510         if (!list)
511                 return 0;
512
513         for_each_dapm_widgets(list, i, widget) {
514                 /* starting widget for playback is AIF type */
515                 if (dir == SNDRV_PCM_STREAM_PLAYBACK && widget->id != snd_soc_dapm_aif_in)
516                         continue;
517
518                 /* starting widget for capture is DAI type */
519                 if (dir == SNDRV_PCM_STREAM_CAPTURE && widget->id != snd_soc_dapm_dai_out)
520                         continue;
521
522                 switch (op) {
523                 case SOF_WIDGET_SETUP:
524                         ret = sof_set_up_widgets_in_path(sdev, widget, dir, spcm);
525                         str = "set up";
526                         break;
527                 case SOF_WIDGET_FREE:
528                         ret = sof_free_widgets_in_path(sdev, widget, dir, spcm);
529                         str = "free";
530                         break;
531                 case SOF_WIDGET_PREPARE:
532                 {
533                         struct snd_pcm_hw_params pipeline_params;
534
535                         str = "prepare";
536                         /*
537                          * When walking the list of connected widgets, the pipeline_params for each
538                          * widget is modified by the source widget in the path. Use a local
539                          * copy of the runtime params as the pipeline_params so that the runtime
540                          * params does not get overwritten.
541                          */
542                         memcpy(&pipeline_params, fe_params, sizeof(*fe_params));
543
544                         ret = sof_prepare_widgets_in_path(sdev, widget, fe_params, platform_params,
545                                                           &pipeline_params, dir, list);
546                         break;
547                 }
548                 case SOF_WIDGET_UNPREPARE:
549                         sof_unprepare_widgets_in_path(sdev, widget, list);
550                         break;
551                 default:
552                         dev_err(sdev->dev, "Invalid widget op %d\n", op);
553                         return -EINVAL;
554                 }
555                 if (ret < 0) {
556                         dev_err(sdev->dev, "Failed to %s connected widgets\n", str);
557                         return ret;
558                 }
559         }
560
561         return 0;
562 }
563
564 int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm,
565                           struct snd_pcm_hw_params *fe_params,
566                           struct snd_sof_platform_stream_params *platform_params,
567                           int dir)
568 {
569         const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
570         struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list;
571         struct snd_soc_dapm_widget *widget;
572         int i, ret;
573
574         /* nothing to set up */
575         if (!list)
576                 return 0;
577
578         /*
579          * Prepare widgets for set up. The prepare step is used to allocate memory, assign
580          * instance ID and pick the widget configuration based on the runtime PCM params.
581          */
582         ret = sof_walk_widgets_in_order(sdev, spcm, fe_params, platform_params,
583                                         dir, SOF_WIDGET_PREPARE);
584         if (ret < 0)
585                 return ret;
586
587         /* Set up is used to send the IPC to the DSP to create the widget */
588         ret = sof_walk_widgets_in_order(sdev, spcm, fe_params, platform_params,
589                                         dir, SOF_WIDGET_SETUP);
590         if (ret < 0) {
591                 ret = sof_walk_widgets_in_order(sdev, spcm, fe_params, platform_params,
592                                                 dir, SOF_WIDGET_UNPREPARE);
593                 return ret;
594         }
595
596         /*
597          * error in setting pipeline connections will result in route status being reset for
598          * routes that were successfully set up when the widgets are freed.
599          */
600         ret = sof_setup_pipeline_connections(sdev, list, dir);
601         if (ret < 0)
602                 goto widget_free;
603
604         /* complete pipelines */
605         for_each_dapm_widgets(list, i, widget) {
606                 struct snd_sof_widget *swidget = widget->dobj.private;
607                 struct snd_sof_widget *pipe_widget;
608                 struct snd_sof_pipeline *spipe;
609
610                 if (!swidget)
611                         continue;
612
613                 spipe = swidget->spipe;
614                 if (!spipe) {
615                         dev_err(sdev->dev, "no pipeline found for %s\n",
616                                 swidget->widget->name);
617                         ret = -EINVAL;
618                         goto widget_free;
619                 }
620
621                 pipe_widget = spipe->pipe_widget;
622                 if (!pipe_widget) {
623                         dev_err(sdev->dev, "error: no pipeline widget found for %s\n",
624                                 swidget->widget->name);
625                         ret = -EINVAL;
626                         goto widget_free;
627                 }
628
629                 if (spipe->complete)
630                         continue;
631
632                 if (tplg_ops && tplg_ops->pipeline_complete) {
633                         spipe->complete = tplg_ops->pipeline_complete(sdev, pipe_widget);
634                         if (spipe->complete < 0) {
635                                 ret = spipe->complete;
636                                 goto widget_free;
637                         }
638                 }
639         }
640
641         return 0;
642
643 widget_free:
644         sof_walk_widgets_in_order(sdev, spcm, fe_params, platform_params, dir,
645                                   SOF_WIDGET_FREE);
646         sof_walk_widgets_in_order(sdev, spcm, NULL, NULL, dir, SOF_WIDGET_UNPREPARE);
647
648         return ret;
649 }
650
651 int sof_widget_list_free(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int dir)
652 {
653         struct snd_sof_pcm_stream_pipeline_list *pipeline_list = &spcm->stream[dir].pipeline_list;
654         struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list;
655         int ret;
656
657         /* nothing to free */
658         if (!list)
659                 return 0;
660
661         /* send IPC to free widget in the DSP */
662         ret = sof_walk_widgets_in_order(sdev, spcm, NULL, NULL, dir, SOF_WIDGET_FREE);
663
664         /* unprepare the widget */
665         sof_walk_widgets_in_order(sdev, spcm, NULL, NULL, dir, SOF_WIDGET_UNPREPARE);
666
667         snd_soc_dapm_dai_free_widgets(&list);
668         spcm->stream[dir].list = NULL;
669
670         pipeline_list->count = 0;
671
672         return ret;
673 }
674
675 /*
676  * helper to determine if there are only D0i3 compatible
677  * streams active
678  */
679 bool snd_sof_dsp_only_d0i3_compatible_stream_active(struct snd_sof_dev *sdev)
680 {
681         struct snd_pcm_substream *substream;
682         struct snd_sof_pcm *spcm;
683         bool d0i3_compatible_active = false;
684         int dir;
685
686         list_for_each_entry(spcm, &sdev->pcm_list, list) {
687                 for_each_pcm_streams(dir) {
688                         substream = spcm->stream[dir].substream;
689                         if (!substream || !substream->runtime)
690                                 continue;
691
692                         /*
693                          * substream->runtime being not NULL indicates
694                          * that the stream is open. No need to check the
695                          * stream state.
696                          */
697                         if (!spcm->stream[dir].d0i3_compatible)
698                                 return false;
699
700                         d0i3_compatible_active = true;
701                 }
702         }
703
704         return d0i3_compatible_active;
705 }
706 EXPORT_SYMBOL(snd_sof_dsp_only_d0i3_compatible_stream_active);
707
708 bool snd_sof_stream_suspend_ignored(struct snd_sof_dev *sdev)
709 {
710         struct snd_sof_pcm *spcm;
711
712         list_for_each_entry(spcm, &sdev->pcm_list, list) {
713                 if (spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].suspend_ignored ||
714                     spcm->stream[SNDRV_PCM_STREAM_CAPTURE].suspend_ignored)
715                         return true;
716         }
717
718         return false;
719 }
720
721 int sof_pcm_stream_free(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream,
722                         struct snd_sof_pcm *spcm, int dir, bool free_widget_list)
723 {
724         const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm);
725         int ret;
726
727         /* Send PCM_FREE IPC to reset pipeline */
728         if (pcm_ops && pcm_ops->hw_free && spcm->prepared[substream->stream]) {
729                 ret = pcm_ops->hw_free(sdev->component, substream);
730                 if (ret < 0)
731                         return ret;
732         }
733
734         spcm->prepared[substream->stream] = false;
735
736         /* stop the DMA */
737         ret = snd_sof_pcm_platform_hw_free(sdev, substream);
738         if (ret < 0)
739                 return ret;
740
741         /* free widget list */
742         if (free_widget_list) {
743                 ret = sof_widget_list_free(sdev, spcm, dir);
744                 if (ret < 0)
745                         dev_err(sdev->dev, "failed to free widgets during suspend\n");
746         }
747
748         return ret;
749 }
750
751 /*
752  * Generic object lookup APIs.
753  */
754
755 struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_soc_component *scomp,
756                                            const char *name)
757 {
758         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
759         struct snd_sof_pcm *spcm;
760
761         list_for_each_entry(spcm, &sdev->pcm_list, list) {
762                 /* match with PCM dai name */
763                 if (strcmp(spcm->pcm.dai_name, name) == 0)
764                         return spcm;
765
766                 /* match with playback caps name if set */
767                 if (*spcm->pcm.caps[0].name &&
768                     !strcmp(spcm->pcm.caps[0].name, name))
769                         return spcm;
770
771                 /* match with capture caps name if set */
772                 if (*spcm->pcm.caps[1].name &&
773                     !strcmp(spcm->pcm.caps[1].name, name))
774                         return spcm;
775         }
776
777         return NULL;
778 }
779
780 struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_soc_component *scomp,
781                                            unsigned int comp_id,
782                                            int *direction)
783 {
784         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
785         struct snd_sof_pcm *spcm;
786         int dir;
787
788         list_for_each_entry(spcm, &sdev->pcm_list, list) {
789                 for_each_pcm_streams(dir) {
790                         if (spcm->stream[dir].comp_id == comp_id) {
791                                 *direction = dir;
792                                 return spcm;
793                         }
794                 }
795         }
796
797         return NULL;
798 }
799
800 struct snd_sof_widget *snd_sof_find_swidget(struct snd_soc_component *scomp,
801                                             const char *name)
802 {
803         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
804         struct snd_sof_widget *swidget;
805
806         list_for_each_entry(swidget, &sdev->widget_list, list) {
807                 if (strcmp(name, swidget->widget->name) == 0)
808                         return swidget;
809         }
810
811         return NULL;
812 }
813
814 /* find widget by stream name and direction */
815 struct snd_sof_widget *
816 snd_sof_find_swidget_sname(struct snd_soc_component *scomp,
817                            const char *pcm_name, int dir)
818 {
819         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
820         struct snd_sof_widget *swidget;
821         enum snd_soc_dapm_type type;
822
823         if (dir == SNDRV_PCM_STREAM_PLAYBACK)
824                 type = snd_soc_dapm_aif_in;
825         else
826                 type = snd_soc_dapm_aif_out;
827
828         list_for_each_entry(swidget, &sdev->widget_list, list) {
829                 if (!strcmp(pcm_name, swidget->widget->sname) &&
830                     swidget->id == type)
831                         return swidget;
832         }
833
834         return NULL;
835 }
836
837 struct snd_sof_dai *snd_sof_find_dai(struct snd_soc_component *scomp,
838                                      const char *name)
839 {
840         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
841         struct snd_sof_dai *dai;
842
843         list_for_each_entry(dai, &sdev->dai_list, list) {
844                 if (dai->name && (strcmp(name, dai->name) == 0))
845                         return dai;
846         }
847
848         return NULL;
849 }
850
851 static int sof_dai_get_clk(struct snd_soc_pcm_runtime *rtd, int clk_type)
852 {
853         struct snd_soc_component *component =
854                 snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME);
855         struct snd_sof_dai *dai =
856                 snd_sof_find_dai(component, (char *)rtd->dai_link->name);
857         struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
858         const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
859
860         /* use the tplg configured mclk if existed */
861         if (!dai)
862                 return 0;
863
864         if (tplg_ops && tplg_ops->dai_get_clk)
865                 return tplg_ops->dai_get_clk(sdev, dai, clk_type);
866
867         return 0;
868 }
869
870 /*
871  * Helper to get SSP MCLK from a pcm_runtime.
872  * Return 0 if not exist.
873  */
874 int sof_dai_get_mclk(struct snd_soc_pcm_runtime *rtd)
875 {
876         return sof_dai_get_clk(rtd, SOF_DAI_CLK_INTEL_SSP_MCLK);
877 }
878 EXPORT_SYMBOL(sof_dai_get_mclk);
879
880 /*
881  * Helper to get SSP BCLK from a pcm_runtime.
882  * Return 0 if not exist.
883  */
884 int sof_dai_get_bclk(struct snd_soc_pcm_runtime *rtd)
885 {
886         return sof_dai_get_clk(rtd, SOF_DAI_CLK_INTEL_SSP_BCLK);
887 }
888 EXPORT_SYMBOL(sof_dai_get_bclk);
889
890 static struct snd_sof_of_mach *sof_of_machine_select(struct snd_sof_dev *sdev)
891 {
892         struct snd_sof_pdata *sof_pdata = sdev->pdata;
893         const struct sof_dev_desc *desc = sof_pdata->desc;
894         struct snd_sof_of_mach *mach = desc->of_machines;
895
896         if (!mach)
897                 return NULL;
898
899         for (; mach->compatible; mach++) {
900                 if (of_machine_is_compatible(mach->compatible)) {
901                         sof_pdata->tplg_filename = mach->sof_tplg_filename;
902                         if (mach->fw_filename)
903                                 sof_pdata->fw_filename = mach->fw_filename;
904
905                         return mach;
906                 }
907         }
908
909         return NULL;
910 }
911
912 /*
913  * SOF Driver enumeration.
914  */
915 int sof_machine_check(struct snd_sof_dev *sdev)
916 {
917         struct snd_sof_pdata *sof_pdata = sdev->pdata;
918         const struct sof_dev_desc *desc = sof_pdata->desc;
919         struct snd_soc_acpi_mach *mach;
920
921         if (!IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE)) {
922                 const struct snd_sof_of_mach *of_mach;
923
924                 if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
925                     sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
926                         goto nocodec;
927
928                 /* find machine */
929                 mach = snd_sof_machine_select(sdev);
930                 if (mach) {
931                         sof_pdata->machine = mach;
932                         snd_sof_set_mach_params(mach, sdev);
933                         return 0;
934                 }
935
936                 of_mach = sof_of_machine_select(sdev);
937                 if (of_mach) {
938                         sof_pdata->of_machine = of_mach;
939                         return 0;
940                 }
941
942                 if (!IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC)) {
943                         dev_err(sdev->dev, "error: no matching ASoC machine driver found - aborting probe\n");
944                         return -ENODEV;
945                 }
946         } else {
947                 dev_warn(sdev->dev, "Force to use nocodec mode\n");
948         }
949
950 nocodec:
951         /* select nocodec mode */
952         dev_warn(sdev->dev, "Using nocodec machine driver\n");
953         mach = devm_kzalloc(sdev->dev, sizeof(*mach), GFP_KERNEL);
954         if (!mach)
955                 return -ENOMEM;
956
957         mach->drv_name = "sof-nocodec";
958         if (!sof_pdata->tplg_filename)
959                 sof_pdata->tplg_filename = desc->nocodec_tplg_filename;
960
961         sof_pdata->machine = mach;
962         snd_sof_set_mach_params(mach, sdev);
963
964         return 0;
965 }
966 EXPORT_SYMBOL(sof_machine_check);
967
968 int sof_machine_register(struct snd_sof_dev *sdev, void *pdata)
969 {
970         struct snd_sof_pdata *plat_data = pdata;
971         const char *drv_name;
972         const void *mach;
973         int size;
974
975         drv_name = plat_data->machine->drv_name;
976         mach = plat_data->machine;
977         size = sizeof(*plat_data->machine);
978
979         /* register machine driver, pass machine info as pdata */
980         plat_data->pdev_mach =
981                 platform_device_register_data(sdev->dev, drv_name,
982                                               PLATFORM_DEVID_NONE, mach, size);
983         if (IS_ERR(plat_data->pdev_mach))
984                 return PTR_ERR(plat_data->pdev_mach);
985
986         dev_dbg(sdev->dev, "created machine %s\n",
987                 dev_name(&plat_data->pdev_mach->dev));
988
989         return 0;
990 }
991 EXPORT_SYMBOL(sof_machine_register);
992
993 void sof_machine_unregister(struct snd_sof_dev *sdev, void *pdata)
994 {
995         struct snd_sof_pdata *plat_data = pdata;
996
997         if (!IS_ERR_OR_NULL(plat_data->pdev_mach))
998                 platform_device_unregister(plat_data->pdev_mach);
999 }
1000 EXPORT_SYMBOL(sof_machine_unregister);