xref: /openbmc/linux/sound/soc/sof/sof-audio.c (revision 67559900)
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 "sof-audio.h"
13 #include "ops.h"
14 
15 static int sof_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
16 {
17 	int ipc_cmd, ctrl_type;
18 	int ret;
19 
20 	/* reset readback offset for scontrol */
21 	scontrol->readback_offset = 0;
22 
23 	/* notify DSP of kcontrol values */
24 	switch (scontrol->cmd) {
25 	case SOF_CTRL_CMD_VOLUME:
26 	case SOF_CTRL_CMD_ENUM:
27 	case SOF_CTRL_CMD_SWITCH:
28 		ipc_cmd = SOF_IPC_COMP_SET_VALUE;
29 		ctrl_type = SOF_CTRL_TYPE_VALUE_CHAN_SET;
30 		break;
31 	case SOF_CTRL_CMD_BINARY:
32 		ipc_cmd = SOF_IPC_COMP_SET_DATA;
33 		ctrl_type = SOF_CTRL_TYPE_DATA_SET;
34 		break;
35 	default:
36 		return 0;
37 	}
38 
39 	ret = snd_sof_ipc_set_get_comp_data(scontrol, ipc_cmd, ctrl_type, scontrol->cmd, true);
40 	if (ret < 0)
41 		dev_err(sdev->dev, "error: failed kcontrol value set for widget: %d\n",
42 			scontrol->comp_id);
43 
44 	return ret;
45 }
46 
47 static int sof_dai_config_setup(struct snd_sof_dev *sdev, struct snd_sof_dai *dai)
48 {
49 	struct sof_ipc_dai_config *config;
50 	struct sof_ipc_reply reply;
51 	int ret;
52 
53 	config = &dai->dai_config[dai->current_config];
54 	if (!config) {
55 		dev_err(sdev->dev, "error: no config for DAI %s\n", dai->name);
56 		return -EINVAL;
57 	}
58 
59 	/* set NONE flag to clear all previous settings */
60 	config->flags = FIELD_PREP(SOF_DAI_CONFIG_FLAGS_MASK, SOF_DAI_CONFIG_FLAGS_NONE);
61 
62 	ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, config->hdr.size,
63 				 &reply, sizeof(reply));
64 
65 	if (ret < 0)
66 		dev_err(sdev->dev, "error: failed to set dai config for %s\n", dai->name);
67 
68 	return ret;
69 }
70 
71 static int sof_widget_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
72 {
73 	struct snd_sof_control *scontrol;
74 	int ret;
75 
76 	/* set up all controls for the widget */
77 	list_for_each_entry(scontrol, &sdev->kcontrol_list, list)
78 		if (scontrol->comp_id == swidget->comp_id) {
79 			ret = sof_kcontrol_setup(sdev, scontrol);
80 			if (ret < 0) {
81 				dev_err(sdev->dev, "error: fail to set up kcontrols for widget %s\n",
82 					swidget->widget->name);
83 				return ret;
84 			}
85 		}
86 
87 	return 0;
88 }
89 
90 static void sof_reset_route_setup_status(struct snd_sof_dev *sdev, struct snd_sof_widget *widget)
91 {
92 	struct snd_sof_route *sroute;
93 
94 	list_for_each_entry(sroute, &sdev->route_list, list)
95 		if (sroute->src_widget == widget || sroute->sink_widget == widget)
96 			sroute->setup = false;
97 }
98 
99 int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
100 {
101 	struct sof_ipc_free ipc_free = {
102 		.hdr = {
103 			.size = sizeof(ipc_free),
104 			.cmd = SOF_IPC_GLB_TPLG_MSG,
105 		},
106 		.id = swidget->comp_id,
107 	};
108 	struct sof_ipc_reply reply;
109 	int ret;
110 
111 	if (!swidget->private)
112 		return 0;
113 
114 	/* only free when use_count is 0 */
115 	if (--swidget->use_count)
116 		return 0;
117 
118 	switch (swidget->id) {
119 	case snd_soc_dapm_scheduler:
120 		ipc_free.hdr.cmd |= SOF_IPC_TPLG_PIPE_FREE;
121 		break;
122 	case snd_soc_dapm_buffer:
123 		ipc_free.hdr.cmd |= SOF_IPC_TPLG_BUFFER_FREE;
124 		break;
125 	default:
126 		ipc_free.hdr.cmd |= SOF_IPC_TPLG_COMP_FREE;
127 		break;
128 	}
129 
130 	ret = sof_ipc_tx_message(sdev->ipc, ipc_free.hdr.cmd, &ipc_free, sizeof(ipc_free),
131 				 &reply, sizeof(reply));
132 	if (ret < 0) {
133 		dev_err(sdev->dev, "error: failed to free widget %s\n", swidget->widget->name);
134 		swidget->use_count++;
135 		return ret;
136 	}
137 
138 	/* reset route setup status for all routes that contain this widget */
139 	sof_reset_route_setup_status(sdev, swidget);
140 	swidget->complete = 0;
141 	dev_dbg(sdev->dev, "widget %s freed\n", swidget->widget->name);
142 
143 	return 0;
144 }
145 EXPORT_SYMBOL(sof_widget_free);
146 
147 int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
148 {
149 	struct sof_ipc_pipe_new *pipeline;
150 	struct sof_ipc_comp_reply r;
151 	struct sof_ipc_cmd_hdr *hdr;
152 	struct sof_ipc_comp *comp;
153 	struct snd_sof_dai *dai;
154 	size_t ipc_size;
155 	int ret;
156 
157 	/* skip if there is no private data */
158 	if (!swidget->private)
159 		return 0;
160 
161 	/* widget already set up */
162 	if (++swidget->use_count > 1)
163 		return 0;
164 
165 	ret = sof_pipeline_core_enable(sdev, swidget);
166 	if (ret < 0) {
167 		dev_err(sdev->dev, "error: failed to enable target core: %d for widget %s\n",
168 			ret, swidget->widget->name);
169 		goto use_count_dec;
170 	}
171 
172 	switch (swidget->id) {
173 	case snd_soc_dapm_dai_in:
174 	case snd_soc_dapm_dai_out:
175 		ipc_size = sizeof(struct sof_ipc_comp_dai) + sizeof(struct sof_ipc_comp_ext);
176 		comp = kzalloc(ipc_size, GFP_KERNEL);
177 		if (!comp)
178 			return -ENOMEM;
179 
180 		dai = swidget->private;
181 		dai->configured = false;
182 		memcpy(comp, &dai->comp_dai, sizeof(struct sof_ipc_comp_dai));
183 
184 		/* append extended data to the end of the component */
185 		memcpy((u8 *)comp + sizeof(struct sof_ipc_comp_dai), &swidget->comp_ext,
186 		       sizeof(swidget->comp_ext));
187 
188 		ret = sof_ipc_tx_message(sdev->ipc, comp->hdr.cmd, comp, ipc_size, &r, sizeof(r));
189 		kfree(comp);
190 		if (ret < 0) {
191 			dev_err(sdev->dev, "error: failed to load widget %s\n",
192 				swidget->widget->name);
193 			goto use_count_dec;
194 		}
195 
196 		ret = sof_dai_config_setup(sdev, dai);
197 		if (ret < 0) {
198 			dev_err(sdev->dev, "error: failed to load dai config for DAI %s\n",
199 				swidget->widget->name);
200 			sof_widget_free(sdev, swidget);
201 			return ret;
202 		}
203 		break;
204 	case snd_soc_dapm_scheduler:
205 		pipeline = swidget->private;
206 		ret = sof_load_pipeline_ipc(sdev, pipeline, &r);
207 		break;
208 	default:
209 		hdr = swidget->private;
210 		ret = sof_ipc_tx_message(sdev->ipc, hdr->cmd, swidget->private, hdr->size,
211 					 &r, sizeof(r));
212 		break;
213 	}
214 	if (ret < 0) {
215 		dev_err(sdev->dev, "error: failed to load widget %s\n", swidget->widget->name);
216 		goto use_count_dec;
217 	}
218 
219 	/* restore kcontrols for widget */
220 	ret = sof_widget_kcontrol_setup(sdev, swidget);
221 	if (ret < 0) {
222 		dev_err(sdev->dev, "error: failed to restore kcontrols for widget %s\n",
223 			swidget->widget->name);
224 		sof_widget_free(sdev, swidget);
225 		return ret;
226 	}
227 
228 	dev_dbg(sdev->dev, "widget %s setup complete\n", swidget->widget->name);
229 
230 	return 0;
231 
232 use_count_dec:
233 	swidget->use_count--;
234 	return ret;
235 }
236 EXPORT_SYMBOL(sof_widget_setup);
237 
238 static int sof_route_setup_ipc(struct snd_sof_dev *sdev, struct snd_sof_route *sroute)
239 {
240 	struct sof_ipc_pipe_comp_connect *connect;
241 	struct sof_ipc_reply reply;
242 	int ret;
243 
244 	/* skip if there's no private data */
245 	if (!sroute->private)
246 		return 0;
247 
248 	/* nothing to do if route is already set up */
249 	if (sroute->setup)
250 		return 0;
251 
252 	connect = sroute->private;
253 
254 	dev_dbg(sdev->dev, "setting up route %s -> %s\n",
255 		sroute->src_widget->widget->name,
256 		sroute->sink_widget->widget->name);
257 
258 	/* send ipc */
259 	ret = sof_ipc_tx_message(sdev->ipc,
260 				 connect->hdr.cmd,
261 				 connect, sizeof(*connect),
262 				 &reply, sizeof(reply));
263 	if (ret < 0) {
264 		dev_err(sdev->dev, "%s: route setup failed %d\n", __func__, ret);
265 		return ret;
266 	}
267 
268 	sroute->setup = true;
269 
270 	return 0;
271 }
272 
273 static int sof_route_setup(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *wsource,
274 			   struct snd_soc_dapm_widget *wsink)
275 {
276 	struct snd_sof_widget *src_widget = wsource->dobj.private;
277 	struct snd_sof_widget *sink_widget = wsink->dobj.private;
278 	struct snd_sof_route *sroute;
279 	bool route_found = false;
280 
281 	/* ignore routes involving virtual widgets in topology */
282 	switch (src_widget->id) {
283 	case snd_soc_dapm_out_drv:
284 	case snd_soc_dapm_output:
285 	case snd_soc_dapm_input:
286 		return 0;
287 	default:
288 		break;
289 	}
290 
291 	switch (sink_widget->id) {
292 	case snd_soc_dapm_out_drv:
293 	case snd_soc_dapm_output:
294 	case snd_soc_dapm_input:
295 		return 0;
296 	default:
297 		break;
298 	}
299 
300 	/* find route matching source and sink widgets */
301 	list_for_each_entry(sroute, &sdev->route_list, list)
302 		if (sroute->src_widget == src_widget && sroute->sink_widget == sink_widget) {
303 			route_found = true;
304 			break;
305 		}
306 
307 	if (!route_found) {
308 		dev_err(sdev->dev, "error: cannot find SOF route for source %s -> %s sink\n",
309 			wsource->name, wsink->name);
310 		return -EINVAL;
311 	}
312 
313 	return sof_route_setup_ipc(sdev, sroute);
314 }
315 
316 static int sof_setup_pipeline_connections(struct snd_sof_dev *sdev,
317 					  struct snd_soc_dapm_widget_list *list, int dir)
318 {
319 	struct snd_soc_dapm_widget *widget;
320 	struct snd_soc_dapm_path *p;
321 	int ret;
322 	int i;
323 
324 	/*
325 	 * Set up connections between widgets in the sink/source paths based on direction.
326 	 * Some non-SOF widgets exist in topology either for compatibility or for the
327 	 * purpose of connecting a pipeline from a host to a DAI in order to receive the DAPM
328 	 * events. But they are not handled by the firmware. So ignore them.
329 	 */
330 	if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
331 		for_each_dapm_widgets(list, i, widget) {
332 			if (!widget->dobj.private)
333 				continue;
334 
335 			snd_soc_dapm_widget_for_each_sink_path(widget, p)
336 				if (p->sink->dobj.private) {
337 					ret = sof_route_setup(sdev, widget, p->sink);
338 					if (ret < 0)
339 						return ret;
340 				}
341 		}
342 	} else {
343 		for_each_dapm_widgets(list, i, widget) {
344 			if (!widget->dobj.private)
345 				continue;
346 
347 			snd_soc_dapm_widget_for_each_source_path(widget, p)
348 				if (p->source->dobj.private) {
349 					ret = sof_route_setup(sdev, p->source, widget);
350 					if (ret < 0)
351 						return ret;
352 				}
353 		}
354 	}
355 
356 	return 0;
357 }
358 
359 int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int dir)
360 {
361 	struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list;
362 	struct snd_soc_dapm_widget *widget;
363 	int i, ret, num_widgets;
364 
365 	/* nothing to set up */
366 	if (!list)
367 		return 0;
368 
369 	/* set up widgets in the list */
370 	for_each_dapm_widgets(list, num_widgets, widget) {
371 		struct snd_sof_widget *swidget = widget->dobj.private;
372 		struct snd_sof_widget *pipe_widget;
373 
374 		if (!swidget)
375 			continue;
376 
377 		/*
378 		 * The scheduler widget for a pipeline is not part of the connected DAPM
379 		 * widget list and it needs to be set up before the widgets in the pipeline
380 		 * are set up. The use_count for the scheduler widget is incremented for every
381 		 * widget in a given pipeline to ensure that it is freed only after the last
382 		 * widget in the pipeline is freed.
383 		 */
384 		pipe_widget = swidget->pipe_widget;
385 		if (!pipe_widget) {
386 			dev_err(sdev->dev, "error: no pipeline widget found for %s\n",
387 				swidget->widget->name);
388 			ret = -EINVAL;
389 			goto widget_free;
390 		}
391 
392 		ret = sof_widget_setup(sdev, pipe_widget);
393 		if (ret < 0)
394 			goto widget_free;
395 
396 		/* set up the widget */
397 		ret = sof_widget_setup(sdev, swidget);
398 		if (ret < 0) {
399 			sof_widget_free(sdev, pipe_widget);
400 			goto widget_free;
401 		}
402 	}
403 
404 	/*
405 	 * error in setting pipeline connections will result in route status being reset for
406 	 * routes that were successfully set up when the widgets are freed.
407 	 */
408 	ret = sof_setup_pipeline_connections(sdev, list, dir);
409 	if (ret < 0)
410 		goto widget_free;
411 
412 	/* complete pipelines */
413 	for_each_dapm_widgets(list, i, widget) {
414 		struct snd_sof_widget *swidget = widget->dobj.private;
415 		struct snd_sof_widget *pipe_widget;
416 
417 		if (!swidget)
418 			continue;
419 
420 		pipe_widget = swidget->pipe_widget;
421 		if (!pipe_widget) {
422 			dev_err(sdev->dev, "error: no pipeline widget found for %s\n",
423 				swidget->widget->name);
424 			ret = -EINVAL;
425 			goto widget_free;
426 		}
427 
428 		if (pipe_widget->complete)
429 			continue;
430 
431 		pipe_widget->complete = snd_sof_complete_pipeline(sdev, pipe_widget);
432 		if (pipe_widget->complete < 0) {
433 			ret = pipe_widget->complete;
434 			goto widget_free;
435 		}
436 	}
437 
438 	return 0;
439 
440 widget_free:
441 	/* free all widgets that have been set up successfully */
442 	for_each_dapm_widgets(list, i, widget) {
443 		struct snd_sof_widget *swidget = widget->dobj.private;
444 
445 		if (!swidget)
446 			continue;
447 
448 		if (!num_widgets--)
449 			break;
450 
451 		sof_widget_free(sdev, swidget);
452 		sof_widget_free(sdev, swidget->pipe_widget);
453 	}
454 
455 	return ret;
456 }
457 
458 int sof_widget_list_free(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int dir)
459 {
460 	struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list;
461 	struct snd_soc_dapm_widget *widget;
462 	int i, ret;
463 	int ret1 = 0;
464 
465 	/* nothing to free */
466 	if (!list)
467 		return 0;
468 
469 	/*
470 	 * Free widgets in the list. This can fail but continue freeing other widgets to keep
471 	 * use_counts balanced.
472 	 */
473 	for_each_dapm_widgets(list, i, widget) {
474 		struct snd_sof_widget *swidget = widget->dobj.private;
475 
476 		if (!swidget)
477 			continue;
478 
479 		/*
480 		 * free widget and its pipe_widget. Either of these can fail, but free as many as
481 		 * possible before freeing the list and returning the error.
482 		 */
483 		ret = sof_widget_free(sdev, swidget);
484 		if (ret < 0)
485 			ret1 = ret;
486 
487 		ret = sof_widget_free(sdev, swidget->pipe_widget);
488 		if (ret < 0)
489 			ret1 = ret;
490 	}
491 
492 	snd_soc_dapm_dai_free_widgets(&list);
493 	spcm->stream[dir].list = NULL;
494 
495 	return ret1;
496 }
497 
498 /*
499  * helper to determine if there are only D0i3 compatible
500  * streams active
501  */
502 bool snd_sof_dsp_only_d0i3_compatible_stream_active(struct snd_sof_dev *sdev)
503 {
504 	struct snd_pcm_substream *substream;
505 	struct snd_sof_pcm *spcm;
506 	bool d0i3_compatible_active = false;
507 	int dir;
508 
509 	list_for_each_entry(spcm, &sdev->pcm_list, list) {
510 		for_each_pcm_streams(dir) {
511 			substream = spcm->stream[dir].substream;
512 			if (!substream || !substream->runtime)
513 				continue;
514 
515 			/*
516 			 * substream->runtime being not NULL indicates
517 			 * that the stream is open. No need to check the
518 			 * stream state.
519 			 */
520 			if (!spcm->stream[dir].d0i3_compatible)
521 				return false;
522 
523 			d0i3_compatible_active = true;
524 		}
525 	}
526 
527 	return d0i3_compatible_active;
528 }
529 EXPORT_SYMBOL(snd_sof_dsp_only_d0i3_compatible_stream_active);
530 
531 bool snd_sof_stream_suspend_ignored(struct snd_sof_dev *sdev)
532 {
533 	struct snd_sof_pcm *spcm;
534 
535 	list_for_each_entry(spcm, &sdev->pcm_list, list) {
536 		if (spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].suspend_ignored ||
537 		    spcm->stream[SNDRV_PCM_STREAM_CAPTURE].suspend_ignored)
538 			return true;
539 	}
540 
541 	return false;
542 }
543 
544 int sof_set_hw_params_upon_resume(struct device *dev)
545 {
546 	struct snd_sof_dev *sdev = dev_get_drvdata(dev);
547 	struct snd_pcm_substream *substream;
548 	struct snd_sof_pcm *spcm;
549 	snd_pcm_state_t state;
550 	int dir;
551 
552 	/*
553 	 * SOF requires hw_params to be set-up internally upon resume.
554 	 * So, set the flag to indicate this for those streams that
555 	 * have been suspended.
556 	 */
557 	list_for_each_entry(spcm, &sdev->pcm_list, list) {
558 		for_each_pcm_streams(dir) {
559 			/*
560 			 * do not reset hw_params upon resume for streams that
561 			 * were kept running during suspend
562 			 */
563 			if (spcm->stream[dir].suspend_ignored)
564 				continue;
565 
566 			substream = spcm->stream[dir].substream;
567 			if (!substream || !substream->runtime)
568 				continue;
569 
570 			state = substream->runtime->status->state;
571 			if (state == SNDRV_PCM_STATE_SUSPENDED)
572 				spcm->prepared[dir] = false;
573 		}
574 	}
575 
576 	/* set internal flag for BE */
577 	return snd_sof_dsp_hw_params_upon_resume(sdev);
578 }
579 
580 const struct sof_ipc_pipe_new *snd_sof_pipeline_find(struct snd_sof_dev *sdev,
581 						     int pipeline_id)
582 {
583 	const struct snd_sof_widget *swidget;
584 
585 	list_for_each_entry(swidget, &sdev->widget_list, list)
586 		if (swidget->id == snd_soc_dapm_scheduler) {
587 			const struct sof_ipc_pipe_new *pipeline =
588 				swidget->private;
589 			if (pipeline->pipeline_id == pipeline_id)
590 				return pipeline;
591 		}
592 
593 	return NULL;
594 }
595 
596 int sof_set_up_pipelines(struct snd_sof_dev *sdev, bool verify)
597 {
598 	struct snd_sof_widget *swidget;
599 	struct snd_sof_route *sroute;
600 	int ret;
601 
602 	/* restore pipeline components */
603 	list_for_each_entry_reverse(swidget, &sdev->widget_list, list) {
604 		/* only set up the widgets belonging to static pipelines */
605 		if (!verify && swidget->dynamic_pipeline_widget)
606 			continue;
607 
608 		/* update DAI config. The IPC will be sent in sof_widget_setup() */
609 		if (WIDGET_IS_DAI(swidget->id)) {
610 			struct snd_sof_dai *dai = swidget->private;
611 			struct sof_ipc_dai_config *config;
612 
613 			if (!dai || !dai->dai_config)
614 				continue;
615 
616 			config = dai->dai_config;
617 			/*
618 			 * The link DMA channel would be invalidated for running
619 			 * streams but not for streams that were in the PAUSED
620 			 * state during suspend. So invalidate it here before setting
621 			 * the dai config in the DSP.
622 			 */
623 			if (config->type == SOF_DAI_INTEL_HDA)
624 				config->hda.link_dma_ch = DMA_CHAN_INVALID;
625 		}
626 
627 		ret = sof_widget_setup(sdev, swidget);
628 		if (ret < 0)
629 			return ret;
630 	}
631 
632 	/* restore pipeline connections */
633 	list_for_each_entry(sroute, &sdev->route_list, list) {
634 
635 		/* only set up routes belonging to static pipelines */
636 		if (!verify && (sroute->src_widget->dynamic_pipeline_widget ||
637 				sroute->sink_widget->dynamic_pipeline_widget))
638 			continue;
639 
640 		ret = sof_route_setup_ipc(sdev, sroute);
641 		if (ret < 0) {
642 			dev_err(sdev->dev, "%s: restore pipeline connections failed\n", __func__);
643 			return ret;
644 		}
645 	}
646 
647 	/* complete pipeline */
648 	list_for_each_entry(swidget, &sdev->widget_list, list) {
649 		switch (swidget->id) {
650 		case snd_soc_dapm_scheduler:
651 			/* only complete static pipelines */
652 			if (!verify && swidget->dynamic_pipeline_widget)
653 				continue;
654 
655 			swidget->complete =
656 				snd_sof_complete_pipeline(sdev, swidget);
657 			break;
658 		default:
659 			break;
660 		}
661 	}
662 
663 	return 0;
664 }
665 
666 /*
667  * This function doesn't free widgets during suspend. It only resets the set up status for all
668  * routes and use_count for all widgets.
669  */
670 int sof_tear_down_pipelines(struct snd_sof_dev *sdev, bool verify)
671 {
672 	struct snd_sof_widget *swidget;
673 	struct snd_sof_route *sroute;
674 	int ret;
675 
676 	/*
677 	 * This function is called during suspend and for one-time topology verification during
678 	 * first boot. In both cases, there is no need to protect swidget->use_count and
679 	 * sroute->setup because during suspend all streams are suspended and during topology
680 	 * loading the sound card unavailable to open PCMs.
681 	 */
682 	list_for_each_entry_reverse(swidget, &sdev->widget_list, list) {
683 		if (!verify) {
684 			swidget->use_count = 0;
685 			continue;
686 		}
687 
688 		ret = sof_widget_free(sdev, swidget);
689 		if (ret < 0)
690 			return ret;
691 	}
692 
693 	list_for_each_entry(sroute, &sdev->route_list, list)
694 		sroute->setup = false;
695 
696 	return 0;
697 }
698 
699 /*
700  * Generic object lookup APIs.
701  */
702 
703 struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_soc_component *scomp,
704 					   const char *name)
705 {
706 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
707 	struct snd_sof_pcm *spcm;
708 
709 	list_for_each_entry(spcm, &sdev->pcm_list, list) {
710 		/* match with PCM dai name */
711 		if (strcmp(spcm->pcm.dai_name, name) == 0)
712 			return spcm;
713 
714 		/* match with playback caps name if set */
715 		if (*spcm->pcm.caps[0].name &&
716 		    !strcmp(spcm->pcm.caps[0].name, name))
717 			return spcm;
718 
719 		/* match with capture caps name if set */
720 		if (*spcm->pcm.caps[1].name &&
721 		    !strcmp(spcm->pcm.caps[1].name, name))
722 			return spcm;
723 	}
724 
725 	return NULL;
726 }
727 
728 struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_soc_component *scomp,
729 					   unsigned int comp_id,
730 					   int *direction)
731 {
732 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
733 	struct snd_sof_pcm *spcm;
734 	int dir;
735 
736 	list_for_each_entry(spcm, &sdev->pcm_list, list) {
737 		for_each_pcm_streams(dir) {
738 			if (spcm->stream[dir].comp_id == comp_id) {
739 				*direction = dir;
740 				return spcm;
741 			}
742 		}
743 	}
744 
745 	return NULL;
746 }
747 
748 struct snd_sof_pcm *snd_sof_find_spcm_pcm_id(struct snd_soc_component *scomp,
749 					     unsigned int pcm_id)
750 {
751 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
752 	struct snd_sof_pcm *spcm;
753 
754 	list_for_each_entry(spcm, &sdev->pcm_list, list) {
755 		if (le32_to_cpu(spcm->pcm.pcm_id) == pcm_id)
756 			return spcm;
757 	}
758 
759 	return NULL;
760 }
761 
762 struct snd_sof_widget *snd_sof_find_swidget(struct snd_soc_component *scomp,
763 					    const char *name)
764 {
765 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
766 	struct snd_sof_widget *swidget;
767 
768 	list_for_each_entry(swidget, &sdev->widget_list, list) {
769 		if (strcmp(name, swidget->widget->name) == 0)
770 			return swidget;
771 	}
772 
773 	return NULL;
774 }
775 
776 /* find widget by stream name and direction */
777 struct snd_sof_widget *
778 snd_sof_find_swidget_sname(struct snd_soc_component *scomp,
779 			   const char *pcm_name, int dir)
780 {
781 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
782 	struct snd_sof_widget *swidget;
783 	enum snd_soc_dapm_type type;
784 
785 	if (dir == SNDRV_PCM_STREAM_PLAYBACK)
786 		type = snd_soc_dapm_aif_in;
787 	else
788 		type = snd_soc_dapm_aif_out;
789 
790 	list_for_each_entry(swidget, &sdev->widget_list, list) {
791 		if (!strcmp(pcm_name, swidget->widget->sname) &&
792 		    swidget->id == type)
793 			return swidget;
794 	}
795 
796 	return NULL;
797 }
798 
799 struct snd_sof_dai *snd_sof_find_dai(struct snd_soc_component *scomp,
800 				     const char *name)
801 {
802 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
803 	struct snd_sof_dai *dai;
804 
805 	list_for_each_entry(dai, &sdev->dai_list, list) {
806 		if (dai->name && (strcmp(name, dai->name) == 0))
807 			return dai;
808 	}
809 
810 	return NULL;
811 }
812 
813 #define SOF_DAI_CLK_INTEL_SSP_MCLK	0
814 #define SOF_DAI_CLK_INTEL_SSP_BCLK	1
815 
816 static int sof_dai_get_clk(struct snd_soc_pcm_runtime *rtd, int clk_type)
817 {
818 	struct snd_soc_component *component =
819 		snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME);
820 	struct snd_sof_dai *dai =
821 		snd_sof_find_dai(component, (char *)rtd->dai_link->name);
822 
823 	/* use the tplg configured mclk if existed */
824 	if (!dai || !dai->dai_config)
825 		return 0;
826 
827 	switch (dai->dai_config->type) {
828 	case SOF_DAI_INTEL_SSP:
829 		switch (clk_type) {
830 		case SOF_DAI_CLK_INTEL_SSP_MCLK:
831 			return dai->dai_config->ssp.mclk_rate;
832 		case SOF_DAI_CLK_INTEL_SSP_BCLK:
833 			return dai->dai_config->ssp.bclk_rate;
834 		default:
835 			dev_err(rtd->dev, "fail to get SSP clk %d rate\n",
836 				clk_type);
837 			return -EINVAL;
838 		}
839 		break;
840 	default:
841 		/* not yet implemented for platforms other than the above */
842 		dev_err(rtd->dev, "DAI type %d not supported yet!\n",
843 			dai->dai_config->type);
844 		return -EINVAL;
845 	}
846 }
847 
848 /*
849  * Helper to get SSP MCLK from a pcm_runtime.
850  * Return 0 if not exist.
851  */
852 int sof_dai_get_mclk(struct snd_soc_pcm_runtime *rtd)
853 {
854 	return sof_dai_get_clk(rtd, SOF_DAI_CLK_INTEL_SSP_MCLK);
855 }
856 EXPORT_SYMBOL(sof_dai_get_mclk);
857 
858 /*
859  * Helper to get SSP BCLK from a pcm_runtime.
860  * Return 0 if not exist.
861  */
862 int sof_dai_get_bclk(struct snd_soc_pcm_runtime *rtd)
863 {
864 	return sof_dai_get_clk(rtd, SOF_DAI_CLK_INTEL_SSP_BCLK);
865 }
866 EXPORT_SYMBOL(sof_dai_get_bclk);
867 
868 /*
869  * SOF Driver enumeration.
870  */
871 int sof_machine_check(struct snd_sof_dev *sdev)
872 {
873 	struct snd_sof_pdata *sof_pdata = sdev->pdata;
874 	const struct sof_dev_desc *desc = sof_pdata->desc;
875 	struct snd_soc_acpi_mach *mach;
876 
877 	if (!IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE)) {
878 
879 		/* find machine */
880 		snd_sof_machine_select(sdev);
881 		if (sof_pdata->machine) {
882 			snd_sof_set_mach_params(sof_pdata->machine, sdev);
883 			return 0;
884 		}
885 
886 		if (!IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC)) {
887 			dev_err(sdev->dev, "error: no matching ASoC machine driver found - aborting probe\n");
888 			return -ENODEV;
889 		}
890 	} else {
891 		dev_warn(sdev->dev, "Force to use nocodec mode\n");
892 	}
893 
894 	/* select nocodec mode */
895 	dev_warn(sdev->dev, "Using nocodec machine driver\n");
896 	mach = devm_kzalloc(sdev->dev, sizeof(*mach), GFP_KERNEL);
897 	if (!mach)
898 		return -ENOMEM;
899 
900 	mach->drv_name = "sof-nocodec";
901 	sof_pdata->tplg_filename = desc->nocodec_tplg_filename;
902 
903 	sof_pdata->machine = mach;
904 	snd_sof_set_mach_params(sof_pdata->machine, sdev);
905 
906 	return 0;
907 }
908 EXPORT_SYMBOL(sof_machine_check);
909 
910 int sof_machine_register(struct snd_sof_dev *sdev, void *pdata)
911 {
912 	struct snd_sof_pdata *plat_data = pdata;
913 	const char *drv_name;
914 	const void *mach;
915 	int size;
916 
917 	drv_name = plat_data->machine->drv_name;
918 	mach = plat_data->machine;
919 	size = sizeof(*plat_data->machine);
920 
921 	/* register machine driver, pass machine info as pdata */
922 	plat_data->pdev_mach =
923 		platform_device_register_data(sdev->dev, drv_name,
924 					      PLATFORM_DEVID_NONE, mach, size);
925 	if (IS_ERR(plat_data->pdev_mach))
926 		return PTR_ERR(plat_data->pdev_mach);
927 
928 	dev_dbg(sdev->dev, "created machine %s\n",
929 		dev_name(&plat_data->pdev_mach->dev));
930 
931 	return 0;
932 }
933 EXPORT_SYMBOL(sof_machine_register);
934 
935 void sof_machine_unregister(struct snd_sof_dev *sdev, void *pdata)
936 {
937 	struct snd_sof_pdata *plat_data = pdata;
938 
939 	if (!IS_ERR_OR_NULL(plat_data->pdev_mach))
940 		platform_device_unregister(plat_data->pdev_mach);
941 }
942 EXPORT_SYMBOL(sof_machine_unregister);
943