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 && swidget->prepared) { 386 widget_ops[widget->id].ipc_unprepare(swidget); 387 swidget->prepared = false; 388 } 389 return ret; 390 } 391 } 392 } 393 394 return 0; 395 } 396 397 /* 398 * free all widgets in the sink path starting from the source widget 399 * (DAI type for capture, AIF type for playback) 400 */ 401 static int sof_free_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget, 402 int dir, struct snd_sof_pcm *spcm) 403 { 404 struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list; 405 struct snd_soc_dapm_path *p; 406 int err; 407 int ret = 0; 408 409 if (widget->dobj.private) { 410 err = sof_widget_free(sdev, widget->dobj.private); 411 if (err < 0) 412 ret = err; 413 } 414 415 /* free all widgets in the sink paths even in case of error to keep use counts balanced */ 416 snd_soc_dapm_widget_for_each_sink_path(widget, p) { 417 if (!p->walking) { 418 if (!widget_in_list(list, p->sink)) 419 continue; 420 421 p->walking = true; 422 423 err = sof_free_widgets_in_path(sdev, p->sink, dir, spcm); 424 if (err < 0) 425 ret = err; 426 p->walking = false; 427 } 428 } 429 430 return ret; 431 } 432 433 /* 434 * set up all widgets in the sink path starting from the source widget 435 * (DAI type for capture, AIF type for playback). 436 * The error path in this function ensures that all successfully set up widgets getting freed. 437 */ 438 static int sof_set_up_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget, 439 int dir, struct snd_sof_pcm *spcm) 440 { 441 struct snd_sof_pcm_stream_pipeline_list *pipeline_list = &spcm->stream[dir].pipeline_list; 442 struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list; 443 struct snd_sof_widget *swidget = widget->dobj.private; 444 struct snd_sof_pipeline *spipe; 445 struct snd_soc_dapm_path *p; 446 int ret; 447 448 if (swidget) { 449 int i; 450 451 ret = sof_widget_setup(sdev, widget->dobj.private); 452 if (ret < 0) 453 return ret; 454 455 /* skip populating the pipe_widgets array if it is NULL */ 456 if (!pipeline_list->pipelines) 457 goto sink_setup; 458 459 /* 460 * Add the widget's pipe_widget to the list of pipelines to be triggered if not 461 * already in the list. This will result in the pipelines getting added in the 462 * order source to sink. 463 */ 464 for (i = 0; i < pipeline_list->count; i++) { 465 spipe = pipeline_list->pipelines[i]; 466 if (spipe == swidget->spipe) 467 break; 468 } 469 470 if (i == pipeline_list->count) { 471 pipeline_list->count++; 472 pipeline_list->pipelines[i] = swidget->spipe; 473 } 474 } 475 476 sink_setup: 477 snd_soc_dapm_widget_for_each_sink_path(widget, p) { 478 if (!p->walking) { 479 if (!widget_in_list(list, p->sink)) 480 continue; 481 482 p->walking = true; 483 484 ret = sof_set_up_widgets_in_path(sdev, p->sink, dir, spcm); 485 p->walking = false; 486 if (ret < 0) { 487 if (swidget) 488 sof_widget_free(sdev, swidget); 489 return ret; 490 } 491 } 492 } 493 494 return 0; 495 } 496 497 static int 498 sof_walk_widgets_in_order(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, 499 struct snd_pcm_hw_params *fe_params, 500 struct snd_sof_platform_stream_params *platform_params, int dir, 501 enum sof_widget_op op) 502 { 503 struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list; 504 struct snd_soc_dapm_widget *widget; 505 char *str; 506 int ret = 0; 507 int i; 508 509 if (!list) 510 return 0; 511 512 for_each_dapm_widgets(list, i, widget) { 513 /* starting widget for playback is AIF type */ 514 if (dir == SNDRV_PCM_STREAM_PLAYBACK && widget->id != snd_soc_dapm_aif_in) 515 continue; 516 517 /* starting widget for capture is DAI type */ 518 if (dir == SNDRV_PCM_STREAM_CAPTURE && widget->id != snd_soc_dapm_dai_out) 519 continue; 520 521 switch (op) { 522 case SOF_WIDGET_SETUP: 523 ret = sof_set_up_widgets_in_path(sdev, widget, dir, spcm); 524 str = "set up"; 525 break; 526 case SOF_WIDGET_FREE: 527 ret = sof_free_widgets_in_path(sdev, widget, dir, spcm); 528 str = "free"; 529 break; 530 case SOF_WIDGET_PREPARE: 531 { 532 struct snd_pcm_hw_params pipeline_params; 533 534 str = "prepare"; 535 /* 536 * When walking the list of connected widgets, the pipeline_params for each 537 * widget is modified by the source widget in the path. Use a local 538 * copy of the runtime params as the pipeline_params so that the runtime 539 * params does not get overwritten. 540 */ 541 memcpy(&pipeline_params, fe_params, sizeof(*fe_params)); 542 543 ret = sof_prepare_widgets_in_path(sdev, widget, fe_params, platform_params, 544 &pipeline_params, dir, list); 545 break; 546 } 547 case SOF_WIDGET_UNPREPARE: 548 sof_unprepare_widgets_in_path(sdev, widget, list); 549 break; 550 default: 551 dev_err(sdev->dev, "Invalid widget op %d\n", op); 552 return -EINVAL; 553 } 554 if (ret < 0) { 555 dev_err(sdev->dev, "Failed to %s connected widgets\n", str); 556 return ret; 557 } 558 } 559 560 return 0; 561 } 562 563 int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, 564 struct snd_pcm_hw_params *fe_params, 565 struct snd_sof_platform_stream_params *platform_params, 566 int dir) 567 { 568 const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); 569 struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list; 570 struct snd_soc_dapm_widget *widget; 571 int i, ret; 572 573 /* nothing to set up */ 574 if (!list) 575 return 0; 576 577 /* 578 * Prepare widgets for set up. The prepare step is used to allocate memory, assign 579 * instance ID and pick the widget configuration based on the runtime PCM params. 580 */ 581 ret = sof_walk_widgets_in_order(sdev, spcm, fe_params, platform_params, 582 dir, SOF_WIDGET_PREPARE); 583 if (ret < 0) 584 return ret; 585 586 /* Set up is used to send the IPC to the DSP to create the widget */ 587 ret = sof_walk_widgets_in_order(sdev, spcm, fe_params, platform_params, 588 dir, SOF_WIDGET_SETUP); 589 if (ret < 0) { 590 ret = sof_walk_widgets_in_order(sdev, spcm, fe_params, platform_params, 591 dir, SOF_WIDGET_UNPREPARE); 592 return ret; 593 } 594 595 /* 596 * error in setting pipeline connections will result in route status being reset for 597 * routes that were successfully set up when the widgets are freed. 598 */ 599 ret = sof_setup_pipeline_connections(sdev, list, dir); 600 if (ret < 0) 601 goto widget_free; 602 603 /* complete pipelines */ 604 for_each_dapm_widgets(list, i, widget) { 605 struct snd_sof_widget *swidget = widget->dobj.private; 606 struct snd_sof_widget *pipe_widget; 607 struct snd_sof_pipeline *spipe; 608 609 if (!swidget) 610 continue; 611 612 spipe = swidget->spipe; 613 if (!spipe) { 614 dev_err(sdev->dev, "no pipeline found for %s\n", 615 swidget->widget->name); 616 ret = -EINVAL; 617 goto widget_free; 618 } 619 620 pipe_widget = spipe->pipe_widget; 621 if (!pipe_widget) { 622 dev_err(sdev->dev, "error: no pipeline widget found for %s\n", 623 swidget->widget->name); 624 ret = -EINVAL; 625 goto widget_free; 626 } 627 628 if (spipe->complete) 629 continue; 630 631 if (tplg_ops && tplg_ops->pipeline_complete) { 632 spipe->complete = tplg_ops->pipeline_complete(sdev, pipe_widget); 633 if (spipe->complete < 0) { 634 ret = spipe->complete; 635 goto widget_free; 636 } 637 } 638 } 639 640 return 0; 641 642 widget_free: 643 sof_walk_widgets_in_order(sdev, spcm, fe_params, platform_params, dir, 644 SOF_WIDGET_FREE); 645 sof_walk_widgets_in_order(sdev, spcm, NULL, NULL, dir, SOF_WIDGET_UNPREPARE); 646 647 return ret; 648 } 649 650 int sof_widget_list_free(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int dir) 651 { 652 struct snd_sof_pcm_stream_pipeline_list *pipeline_list = &spcm->stream[dir].pipeline_list; 653 struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list; 654 int ret; 655 656 /* nothing to free */ 657 if (!list) 658 return 0; 659 660 /* send IPC to free widget in the DSP */ 661 ret = sof_walk_widgets_in_order(sdev, spcm, NULL, NULL, dir, SOF_WIDGET_FREE); 662 663 /* unprepare the widget */ 664 sof_walk_widgets_in_order(sdev, spcm, NULL, NULL, dir, SOF_WIDGET_UNPREPARE); 665 666 snd_soc_dapm_dai_free_widgets(&list); 667 spcm->stream[dir].list = NULL; 668 669 pipeline_list->count = 0; 670 671 return ret; 672 } 673 674 /* 675 * helper to determine if there are only D0i3 compatible 676 * streams active 677 */ 678 bool snd_sof_dsp_only_d0i3_compatible_stream_active(struct snd_sof_dev *sdev) 679 { 680 struct snd_pcm_substream *substream; 681 struct snd_sof_pcm *spcm; 682 bool d0i3_compatible_active = false; 683 int dir; 684 685 list_for_each_entry(spcm, &sdev->pcm_list, list) { 686 for_each_pcm_streams(dir) { 687 substream = spcm->stream[dir].substream; 688 if (!substream || !substream->runtime) 689 continue; 690 691 /* 692 * substream->runtime being not NULL indicates 693 * that the stream is open. No need to check the 694 * stream state. 695 */ 696 if (!spcm->stream[dir].d0i3_compatible) 697 return false; 698 699 d0i3_compatible_active = true; 700 } 701 } 702 703 return d0i3_compatible_active; 704 } 705 EXPORT_SYMBOL(snd_sof_dsp_only_d0i3_compatible_stream_active); 706 707 bool snd_sof_stream_suspend_ignored(struct snd_sof_dev *sdev) 708 { 709 struct snd_sof_pcm *spcm; 710 711 list_for_each_entry(spcm, &sdev->pcm_list, list) { 712 if (spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].suspend_ignored || 713 spcm->stream[SNDRV_PCM_STREAM_CAPTURE].suspend_ignored) 714 return true; 715 } 716 717 return false; 718 } 719 720 int sof_pcm_stream_free(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, 721 struct snd_sof_pcm *spcm, int dir, bool free_widget_list) 722 { 723 const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); 724 int ret; 725 726 /* Send PCM_FREE IPC to reset pipeline */ 727 if (pcm_ops && pcm_ops->hw_free && spcm->prepared[substream->stream]) { 728 ret = pcm_ops->hw_free(sdev->component, substream); 729 if (ret < 0) 730 return ret; 731 } 732 733 spcm->prepared[substream->stream] = false; 734 735 /* stop the DMA */ 736 ret = snd_sof_pcm_platform_hw_free(sdev, substream); 737 if (ret < 0) 738 return ret; 739 740 /* free widget list */ 741 if (free_widget_list) { 742 ret = sof_widget_list_free(sdev, spcm, dir); 743 if (ret < 0) 744 dev_err(sdev->dev, "failed to free widgets during suspend\n"); 745 } 746 747 return ret; 748 } 749 750 /* 751 * Generic object lookup APIs. 752 */ 753 754 struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_soc_component *scomp, 755 const char *name) 756 { 757 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 758 struct snd_sof_pcm *spcm; 759 760 list_for_each_entry(spcm, &sdev->pcm_list, list) { 761 /* match with PCM dai name */ 762 if (strcmp(spcm->pcm.dai_name, name) == 0) 763 return spcm; 764 765 /* match with playback caps name if set */ 766 if (*spcm->pcm.caps[0].name && 767 !strcmp(spcm->pcm.caps[0].name, name)) 768 return spcm; 769 770 /* match with capture caps name if set */ 771 if (*spcm->pcm.caps[1].name && 772 !strcmp(spcm->pcm.caps[1].name, name)) 773 return spcm; 774 } 775 776 return NULL; 777 } 778 779 struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_soc_component *scomp, 780 unsigned int comp_id, 781 int *direction) 782 { 783 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 784 struct snd_sof_pcm *spcm; 785 int dir; 786 787 list_for_each_entry(spcm, &sdev->pcm_list, list) { 788 for_each_pcm_streams(dir) { 789 if (spcm->stream[dir].comp_id == comp_id) { 790 *direction = dir; 791 return spcm; 792 } 793 } 794 } 795 796 return NULL; 797 } 798 799 struct snd_sof_widget *snd_sof_find_swidget(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_widget *swidget; 804 805 list_for_each_entry(swidget, &sdev->widget_list, list) { 806 if (strcmp(name, swidget->widget->name) == 0) 807 return swidget; 808 } 809 810 return NULL; 811 } 812 813 /* find widget by stream name and direction */ 814 struct snd_sof_widget * 815 snd_sof_find_swidget_sname(struct snd_soc_component *scomp, 816 const char *pcm_name, int dir) 817 { 818 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 819 struct snd_sof_widget *swidget; 820 enum snd_soc_dapm_type type; 821 822 if (dir == SNDRV_PCM_STREAM_PLAYBACK) 823 type = snd_soc_dapm_aif_in; 824 else 825 type = snd_soc_dapm_aif_out; 826 827 list_for_each_entry(swidget, &sdev->widget_list, list) { 828 if (!strcmp(pcm_name, swidget->widget->sname) && 829 swidget->id == type) 830 return swidget; 831 } 832 833 return NULL; 834 } 835 836 struct snd_sof_dai *snd_sof_find_dai(struct snd_soc_component *scomp, 837 const char *name) 838 { 839 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 840 struct snd_sof_dai *dai; 841 842 list_for_each_entry(dai, &sdev->dai_list, list) { 843 if (dai->name && (strcmp(name, dai->name) == 0)) 844 return dai; 845 } 846 847 return NULL; 848 } 849 850 static int sof_dai_get_clk(struct snd_soc_pcm_runtime *rtd, int clk_type) 851 { 852 struct snd_soc_component *component = 853 snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME); 854 struct snd_sof_dai *dai = 855 snd_sof_find_dai(component, (char *)rtd->dai_link->name); 856 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); 857 const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg); 858 859 /* use the tplg configured mclk if existed */ 860 if (!dai) 861 return 0; 862 863 if (tplg_ops && tplg_ops->dai_get_clk) 864 return tplg_ops->dai_get_clk(sdev, dai, clk_type); 865 866 return 0; 867 } 868 869 /* 870 * Helper to get SSP MCLK from a pcm_runtime. 871 * Return 0 if not exist. 872 */ 873 int sof_dai_get_mclk(struct snd_soc_pcm_runtime *rtd) 874 { 875 return sof_dai_get_clk(rtd, SOF_DAI_CLK_INTEL_SSP_MCLK); 876 } 877 EXPORT_SYMBOL(sof_dai_get_mclk); 878 879 /* 880 * Helper to get SSP BCLK from a pcm_runtime. 881 * Return 0 if not exist. 882 */ 883 int sof_dai_get_bclk(struct snd_soc_pcm_runtime *rtd) 884 { 885 return sof_dai_get_clk(rtd, SOF_DAI_CLK_INTEL_SSP_BCLK); 886 } 887 EXPORT_SYMBOL(sof_dai_get_bclk); 888 889 static struct snd_sof_of_mach *sof_of_machine_select(struct snd_sof_dev *sdev) 890 { 891 struct snd_sof_pdata *sof_pdata = sdev->pdata; 892 const struct sof_dev_desc *desc = sof_pdata->desc; 893 struct snd_sof_of_mach *mach = desc->of_machines; 894 895 if (!mach) 896 return NULL; 897 898 for (; mach->compatible; mach++) { 899 if (of_machine_is_compatible(mach->compatible)) { 900 sof_pdata->tplg_filename = mach->sof_tplg_filename; 901 if (mach->fw_filename) 902 sof_pdata->fw_filename = mach->fw_filename; 903 904 return mach; 905 } 906 } 907 908 return NULL; 909 } 910 911 /* 912 * SOF Driver enumeration. 913 */ 914 int sof_machine_check(struct snd_sof_dev *sdev) 915 { 916 struct snd_sof_pdata *sof_pdata = sdev->pdata; 917 const struct sof_dev_desc *desc = sof_pdata->desc; 918 struct snd_soc_acpi_mach *mach; 919 920 if (!IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE)) { 921 const struct snd_sof_of_mach *of_mach; 922 923 if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) && 924 sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC)) 925 goto nocodec; 926 927 /* find machine */ 928 mach = snd_sof_machine_select(sdev); 929 if (mach) { 930 sof_pdata->machine = mach; 931 snd_sof_set_mach_params(mach, sdev); 932 return 0; 933 } 934 935 of_mach = sof_of_machine_select(sdev); 936 if (of_mach) { 937 sof_pdata->of_machine = of_mach; 938 return 0; 939 } 940 941 if (!IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC)) { 942 dev_err(sdev->dev, "error: no matching ASoC machine driver found - aborting probe\n"); 943 return -ENODEV; 944 } 945 } else { 946 dev_warn(sdev->dev, "Force to use nocodec mode\n"); 947 } 948 949 nocodec: 950 /* select nocodec mode */ 951 dev_warn(sdev->dev, "Using nocodec machine driver\n"); 952 mach = devm_kzalloc(sdev->dev, sizeof(*mach), GFP_KERNEL); 953 if (!mach) 954 return -ENOMEM; 955 956 mach->drv_name = "sof-nocodec"; 957 if (!sof_pdata->tplg_filename) 958 sof_pdata->tplg_filename = desc->nocodec_tplg_filename; 959 960 sof_pdata->machine = mach; 961 snd_sof_set_mach_params(mach, sdev); 962 963 return 0; 964 } 965 EXPORT_SYMBOL(sof_machine_check); 966 967 int sof_machine_register(struct snd_sof_dev *sdev, void *pdata) 968 { 969 struct snd_sof_pdata *plat_data = pdata; 970 const char *drv_name; 971 const void *mach; 972 int size; 973 974 drv_name = plat_data->machine->drv_name; 975 mach = plat_data->machine; 976 size = sizeof(*plat_data->machine); 977 978 /* register machine driver, pass machine info as pdata */ 979 plat_data->pdev_mach = 980 platform_device_register_data(sdev->dev, drv_name, 981 PLATFORM_DEVID_NONE, mach, size); 982 if (IS_ERR(plat_data->pdev_mach)) 983 return PTR_ERR(plat_data->pdev_mach); 984 985 dev_dbg(sdev->dev, "created machine %s\n", 986 dev_name(&plat_data->pdev_mach->dev)); 987 988 return 0; 989 } 990 EXPORT_SYMBOL(sof_machine_register); 991 992 void sof_machine_unregister(struct snd_sof_dev *sdev, void *pdata) 993 { 994 struct snd_sof_pdata *plat_data = pdata; 995 996 if (!IS_ERR_OR_NULL(plat_data->pdev_mach)) 997 platform_device_unregister(plat_data->pdev_mach); 998 } 999 EXPORT_SYMBOL(sof_machine_unregister); 1000