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