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 <[email protected]> 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 = sdev->ipc->ops->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->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 = sdev->ipc->ops->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->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 = sdev->ipc->ops->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->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->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->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 *ipc_tplg_ops = sdev->ipc->ops->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 int ret; 178 179 /* ignore routes involving virtual widgets in topology */ 180 switch (src_widget->id) { 181 case snd_soc_dapm_out_drv: 182 case snd_soc_dapm_output: 183 case snd_soc_dapm_input: 184 return 0; 185 default: 186 break; 187 } 188 189 switch (sink_widget->id) { 190 case snd_soc_dapm_out_drv: 191 case snd_soc_dapm_output: 192 case snd_soc_dapm_input: 193 return 0; 194 default: 195 break; 196 } 197 198 /* find route matching source and sink widgets */ 199 list_for_each_entry(sroute, &sdev->route_list, list) 200 if (sroute->src_widget == src_widget && sroute->sink_widget == sink_widget) { 201 route_found = true; 202 break; 203 } 204 205 if (!route_found) { 206 dev_err(sdev->dev, "error: cannot find SOF route for source %s -> %s sink\n", 207 wsource->name, wsink->name); 208 return -EINVAL; 209 } 210 211 /* nothing to do if route is already set up */ 212 if (sroute->setup) 213 return 0; 214 215 ret = ipc_tplg_ops->route_setup(sdev, sroute); 216 if (ret < 0) 217 return ret; 218 219 sroute->setup = true; 220 return 0; 221 } 222 223 static int sof_setup_pipeline_connections(struct snd_sof_dev *sdev, 224 struct snd_soc_dapm_widget_list *list, int dir) 225 { 226 struct snd_soc_dapm_widget *widget; 227 struct snd_soc_dapm_path *p; 228 int ret; 229 int i; 230 231 /* 232 * Set up connections between widgets in the sink/source paths based on direction. 233 * Some non-SOF widgets exist in topology either for compatibility or for the 234 * purpose of connecting a pipeline from a host to a DAI in order to receive the DAPM 235 * events. But they are not handled by the firmware. So ignore them. 236 */ 237 if (dir == SNDRV_PCM_STREAM_PLAYBACK) { 238 for_each_dapm_widgets(list, i, widget) { 239 if (!widget->dobj.private) 240 continue; 241 242 snd_soc_dapm_widget_for_each_sink_path(widget, p) 243 if (p->sink->dobj.private) { 244 ret = sof_route_setup(sdev, widget, p->sink); 245 if (ret < 0) 246 return ret; 247 } 248 } 249 } else { 250 for_each_dapm_widgets(list, i, widget) { 251 if (!widget->dobj.private) 252 continue; 253 254 snd_soc_dapm_widget_for_each_source_path(widget, p) 255 if (p->source->dobj.private) { 256 ret = sof_route_setup(sdev, p->source, widget); 257 if (ret < 0) 258 return ret; 259 } 260 } 261 } 262 263 return 0; 264 } 265 266 static void 267 sof_unprepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget) 268 { 269 const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; 270 const struct sof_ipc_tplg_widget_ops *widget_ops = ipc_tplg_ops->widget; 271 struct snd_sof_widget *swidget = widget->dobj.private; 272 struct snd_soc_dapm_path *p; 273 274 if (!widget_ops[widget->id].ipc_unprepare || !swidget->prepared) 275 goto sink_unprepare; 276 277 /* unprepare the source widget */ 278 widget_ops[widget->id].ipc_unprepare(swidget); 279 swidget->prepared = false; 280 281 sink_unprepare: 282 /* unprepare all widgets in the sink paths */ 283 snd_soc_dapm_widget_for_each_sink_path(widget, p) { 284 if (!p->walking && p->sink->dobj.private) { 285 p->walking = true; 286 sof_unprepare_widgets_in_path(sdev, p->sink); 287 p->walking = false; 288 } 289 } 290 } 291 292 static int 293 sof_prepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget, 294 struct snd_pcm_hw_params *fe_params, 295 struct snd_sof_platform_stream_params *platform_params, 296 struct snd_pcm_hw_params *pipeline_params, int dir) 297 { 298 const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; 299 const struct sof_ipc_tplg_widget_ops *widget_ops = ipc_tplg_ops->widget; 300 struct snd_sof_widget *swidget = widget->dobj.private; 301 struct snd_soc_dapm_path *p; 302 int ret; 303 304 if (!widget_ops[widget->id].ipc_prepare || swidget->prepared) 305 goto sink_prepare; 306 307 /* prepare the source widget */ 308 ret = widget_ops[widget->id].ipc_prepare(swidget, fe_params, platform_params, 309 pipeline_params, dir); 310 if (ret < 0) { 311 dev_err(sdev->dev, "failed to prepare widget %s\n", widget->name); 312 return ret; 313 } 314 315 swidget->prepared = true; 316 317 sink_prepare: 318 /* prepare all widgets in the sink paths */ 319 snd_soc_dapm_widget_for_each_sink_path(widget, p) { 320 if (!p->walking && p->sink->dobj.private) { 321 p->walking = true; 322 ret = sof_prepare_widgets_in_path(sdev, p->sink, fe_params, 323 platform_params, pipeline_params, dir); 324 p->walking = false; 325 if (ret < 0) { 326 /* unprepare the source widget */ 327 if (widget_ops[widget->id].ipc_unprepare && swidget->prepared) { 328 widget_ops[widget->id].ipc_unprepare(swidget); 329 swidget->prepared = false; 330 } 331 return ret; 332 } 333 } 334 } 335 336 return 0; 337 } 338 339 /* 340 * free all widgets in the sink path starting from the source widget 341 * (DAI type for capture, AIF type for playback) 342 */ 343 static int sof_free_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget, 344 int dir) 345 { 346 struct snd_soc_dapm_path *p; 347 int err; 348 int ret = 0; 349 350 /* free all widgets even in case of error to keep use counts balanced */ 351 snd_soc_dapm_widget_for_each_sink_path(widget, p) { 352 if (!p->walking && p->sink->dobj.private && widget->dobj.private) { 353 p->walking = true; 354 if (WIDGET_IS_AIF_OR_DAI(widget->id)) { 355 err = sof_widget_free(sdev, widget->dobj.private); 356 if (err < 0) 357 ret = err; 358 } 359 360 err = sof_widget_free(sdev, p->sink->dobj.private); 361 if (err < 0) 362 ret = err; 363 364 err = sof_free_widgets_in_path(sdev, p->sink, dir); 365 if (err < 0) 366 ret = err; 367 p->walking = false; 368 } 369 } 370 371 return ret; 372 } 373 374 /* 375 * set up all widgets in the sink path starting from the source widget 376 * (DAI type for capture, AIF type for playback). 377 * The error path in this function ensures that all successfully set up widgets getting freed. 378 */ 379 static int sof_set_up_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget, 380 int dir) 381 { 382 struct snd_soc_dapm_path *p; 383 int ret; 384 385 snd_soc_dapm_widget_for_each_sink_path(widget, p) { 386 if (!p->walking && p->sink->dobj.private && widget->dobj.private) { 387 p->walking = true; 388 if (WIDGET_IS_AIF_OR_DAI(widget->id)) { 389 ret = sof_widget_setup(sdev, widget->dobj.private); 390 if (ret < 0) 391 goto out; 392 } 393 394 ret = sof_widget_setup(sdev, p->sink->dobj.private); 395 if (ret < 0) { 396 if (WIDGET_IS_AIF_OR_DAI(widget->id)) 397 sof_widget_free(sdev, widget->dobj.private); 398 goto out; 399 } 400 401 ret = sof_set_up_widgets_in_path(sdev, p->sink, dir); 402 if (ret < 0) { 403 if (WIDGET_IS_AIF_OR_DAI(widget->id)) 404 sof_widget_free(sdev, widget->dobj.private); 405 sof_widget_free(sdev, p->sink->dobj.private); 406 } 407 out: 408 p->walking = false; 409 if (ret < 0) 410 return ret; 411 } 412 } 413 414 return 0; 415 } 416 417 static int 418 sof_walk_widgets_in_order(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget_list *list, 419 struct snd_pcm_hw_params *fe_params, 420 struct snd_sof_platform_stream_params *platform_params, int dir, 421 enum sof_widget_op op) 422 { 423 struct snd_soc_dapm_widget *widget; 424 char *str; 425 int ret = 0; 426 int i; 427 428 for_each_dapm_widgets(list, i, widget) { 429 /* starting widget for playback is AIF type */ 430 if (dir == SNDRV_PCM_STREAM_PLAYBACK && !WIDGET_IS_AIF(widget->id)) 431 continue; 432 433 /* starting widget for capture is DAI type */ 434 if (dir == SNDRV_PCM_STREAM_CAPTURE && !WIDGET_IS_DAI(widget->id)) 435 continue; 436 437 switch (op) { 438 case SOF_WIDGET_SETUP: 439 ret = sof_set_up_widgets_in_path(sdev, widget, dir); 440 str = "set up"; 441 break; 442 case SOF_WIDGET_FREE: 443 ret = sof_free_widgets_in_path(sdev, widget, dir); 444 str = "free"; 445 break; 446 case SOF_WIDGET_PREPARE: 447 { 448 struct snd_pcm_hw_params pipeline_params; 449 450 str = "prepare"; 451 /* 452 * When walking the list of connected widgets, the pipeline_params for each 453 * widget is modified by the source widget in the path. Use a local 454 * copy of the runtime params as the pipeline_params so that the runtime 455 * params does not get overwritten. 456 */ 457 memcpy(&pipeline_params, fe_params, sizeof(*fe_params)); 458 459 ret = sof_prepare_widgets_in_path(sdev, widget, fe_params, 460 platform_params, &pipeline_params, dir); 461 break; 462 } 463 case SOF_WIDGET_UNPREPARE: 464 sof_unprepare_widgets_in_path(sdev, widget); 465 break; 466 default: 467 dev_err(sdev->dev, "Invalid widget op %d\n", op); 468 return -EINVAL; 469 } 470 if (ret < 0) { 471 dev_err(sdev->dev, "Failed to %s connected widgets\n", str); 472 return ret; 473 } 474 } 475 476 return 0; 477 } 478 479 int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, 480 struct snd_pcm_hw_params *fe_params, 481 struct snd_sof_platform_stream_params *platform_params, 482 int dir) 483 { 484 const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; 485 struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list; 486 struct snd_soc_dapm_widget *widget; 487 int i, ret; 488 489 /* nothing to set up */ 490 if (!list) 491 return 0; 492 493 /* 494 * Prepare widgets for set up. The prepare step is used to allocate memory, assign 495 * instance ID and pick the widget configuration based on the runtime PCM params. 496 */ 497 ret = sof_walk_widgets_in_order(sdev, list, fe_params, platform_params, 498 dir, SOF_WIDGET_PREPARE); 499 if (ret < 0) 500 return ret; 501 502 /* Set up is used to send the IPC to the DSP to create the widget */ 503 ret = sof_walk_widgets_in_order(sdev, list, fe_params, platform_params, 504 dir, SOF_WIDGET_SETUP); 505 if (ret < 0) { 506 ret = sof_walk_widgets_in_order(sdev, list, fe_params, platform_params, 507 dir, SOF_WIDGET_UNPREPARE); 508 return ret; 509 } 510 511 /* 512 * error in setting pipeline connections will result in route status being reset for 513 * routes that were successfully set up when the widgets are freed. 514 */ 515 ret = sof_setup_pipeline_connections(sdev, list, dir); 516 if (ret < 0) 517 goto widget_free; 518 519 /* complete pipelines */ 520 for_each_dapm_widgets(list, i, widget) { 521 struct snd_sof_widget *swidget = widget->dobj.private; 522 struct snd_sof_widget *pipe_widget; 523 524 if (!swidget) 525 continue; 526 527 pipe_widget = swidget->pipe_widget; 528 if (!pipe_widget) { 529 dev_err(sdev->dev, "error: no pipeline widget found for %s\n", 530 swidget->widget->name); 531 ret = -EINVAL; 532 goto widget_free; 533 } 534 535 if (pipe_widget->complete) 536 continue; 537 538 if (ipc_tplg_ops->pipeline_complete) { 539 pipe_widget->complete = ipc_tplg_ops->pipeline_complete(sdev, pipe_widget); 540 if (pipe_widget->complete < 0) { 541 ret = pipe_widget->complete; 542 goto widget_free; 543 } 544 } 545 } 546 547 return 0; 548 549 widget_free: 550 sof_walk_widgets_in_order(sdev, list, fe_params, platform_params, dir, 551 SOF_WIDGET_FREE); 552 sof_walk_widgets_in_order(sdev, list, NULL, NULL, dir, SOF_WIDGET_UNPREPARE); 553 554 return ret; 555 } 556 557 int sof_widget_list_free(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int dir) 558 { 559 struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list; 560 int ret; 561 562 /* nothing to free */ 563 if (!list) 564 return 0; 565 566 /* send IPC to free widget in the DSP */ 567 ret = sof_walk_widgets_in_order(sdev, list, NULL, NULL, dir, SOF_WIDGET_FREE); 568 569 /* unprepare the widget */ 570 sof_walk_widgets_in_order(sdev, list, NULL, NULL, dir, SOF_WIDGET_UNPREPARE); 571 572 snd_soc_dapm_dai_free_widgets(&list); 573 spcm->stream[dir].list = NULL; 574 575 return ret; 576 } 577 578 /* 579 * helper to determine if there are only D0i3 compatible 580 * streams active 581 */ 582 bool snd_sof_dsp_only_d0i3_compatible_stream_active(struct snd_sof_dev *sdev) 583 { 584 struct snd_pcm_substream *substream; 585 struct snd_sof_pcm *spcm; 586 bool d0i3_compatible_active = false; 587 int dir; 588 589 list_for_each_entry(spcm, &sdev->pcm_list, list) { 590 for_each_pcm_streams(dir) { 591 substream = spcm->stream[dir].substream; 592 if (!substream || !substream->runtime) 593 continue; 594 595 /* 596 * substream->runtime being not NULL indicates 597 * that the stream is open. No need to check the 598 * stream state. 599 */ 600 if (!spcm->stream[dir].d0i3_compatible) 601 return false; 602 603 d0i3_compatible_active = true; 604 } 605 } 606 607 return d0i3_compatible_active; 608 } 609 EXPORT_SYMBOL(snd_sof_dsp_only_d0i3_compatible_stream_active); 610 611 bool snd_sof_stream_suspend_ignored(struct snd_sof_dev *sdev) 612 { 613 struct snd_sof_pcm *spcm; 614 615 list_for_each_entry(spcm, &sdev->pcm_list, list) { 616 if (spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].suspend_ignored || 617 spcm->stream[SNDRV_PCM_STREAM_CAPTURE].suspend_ignored) 618 return true; 619 } 620 621 return false; 622 } 623 624 int sof_pcm_stream_free(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, 625 struct snd_sof_pcm *spcm, int dir, bool free_widget_list) 626 { 627 const struct sof_ipc_pcm_ops *pcm_ops = sdev->ipc->ops->pcm; 628 int ret; 629 630 /* Send PCM_FREE IPC to reset pipeline */ 631 if (pcm_ops->hw_free && spcm->prepared[substream->stream]) { 632 ret = pcm_ops->hw_free(sdev->component, substream); 633 if (ret < 0) 634 return ret; 635 } 636 637 spcm->prepared[substream->stream] = false; 638 639 /* stop the DMA */ 640 ret = snd_sof_pcm_platform_hw_free(sdev, substream); 641 if (ret < 0) 642 return ret; 643 644 /* free widget list */ 645 if (free_widget_list) { 646 ret = sof_widget_list_free(sdev, spcm, dir); 647 if (ret < 0) 648 dev_err(sdev->dev, "failed to free widgets during suspend\n"); 649 } 650 651 return ret; 652 } 653 654 /* 655 * Generic object lookup APIs. 656 */ 657 658 struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_soc_component *scomp, 659 const char *name) 660 { 661 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 662 struct snd_sof_pcm *spcm; 663 664 list_for_each_entry(spcm, &sdev->pcm_list, list) { 665 /* match with PCM dai name */ 666 if (strcmp(spcm->pcm.dai_name, name) == 0) 667 return spcm; 668 669 /* match with playback caps name if set */ 670 if (*spcm->pcm.caps[0].name && 671 !strcmp(spcm->pcm.caps[0].name, name)) 672 return spcm; 673 674 /* match with capture caps name if set */ 675 if (*spcm->pcm.caps[1].name && 676 !strcmp(spcm->pcm.caps[1].name, name)) 677 return spcm; 678 } 679 680 return NULL; 681 } 682 683 struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_soc_component *scomp, 684 unsigned int comp_id, 685 int *direction) 686 { 687 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 688 struct snd_sof_pcm *spcm; 689 int dir; 690 691 list_for_each_entry(spcm, &sdev->pcm_list, list) { 692 for_each_pcm_streams(dir) { 693 if (spcm->stream[dir].comp_id == comp_id) { 694 *direction = dir; 695 return spcm; 696 } 697 } 698 } 699 700 return NULL; 701 } 702 703 struct snd_sof_widget *snd_sof_find_swidget(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_widget *swidget; 708 709 list_for_each_entry(swidget, &sdev->widget_list, list) { 710 if (strcmp(name, swidget->widget->name) == 0) 711 return swidget; 712 } 713 714 return NULL; 715 } 716 717 /* find widget by stream name and direction */ 718 struct snd_sof_widget * 719 snd_sof_find_swidget_sname(struct snd_soc_component *scomp, 720 const char *pcm_name, int dir) 721 { 722 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 723 struct snd_sof_widget *swidget; 724 enum snd_soc_dapm_type type; 725 726 if (dir == SNDRV_PCM_STREAM_PLAYBACK) 727 type = snd_soc_dapm_aif_in; 728 else 729 type = snd_soc_dapm_aif_out; 730 731 list_for_each_entry(swidget, &sdev->widget_list, list) { 732 if (!strcmp(pcm_name, swidget->widget->sname) && 733 swidget->id == type) 734 return swidget; 735 } 736 737 return NULL; 738 } 739 740 struct snd_sof_dai *snd_sof_find_dai(struct snd_soc_component *scomp, 741 const char *name) 742 { 743 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 744 struct snd_sof_dai *dai; 745 746 list_for_each_entry(dai, &sdev->dai_list, list) { 747 if (dai->name && (strcmp(name, dai->name) == 0)) 748 return dai; 749 } 750 751 return NULL; 752 } 753 754 static int sof_dai_get_clk(struct snd_soc_pcm_runtime *rtd, int clk_type) 755 { 756 struct snd_soc_component *component = 757 snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME); 758 struct snd_sof_dai *dai = 759 snd_sof_find_dai(component, (char *)rtd->dai_link->name); 760 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); 761 const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; 762 763 /* use the tplg configured mclk if existed */ 764 if (!dai) 765 return 0; 766 767 if (tplg_ops->dai_get_clk) 768 return tplg_ops->dai_get_clk(sdev, dai, clk_type); 769 770 return 0; 771 } 772 773 /* 774 * Helper to get SSP MCLK from a pcm_runtime. 775 * Return 0 if not exist. 776 */ 777 int sof_dai_get_mclk(struct snd_soc_pcm_runtime *rtd) 778 { 779 return sof_dai_get_clk(rtd, SOF_DAI_CLK_INTEL_SSP_MCLK); 780 } 781 EXPORT_SYMBOL(sof_dai_get_mclk); 782 783 /* 784 * Helper to get SSP BCLK from a pcm_runtime. 785 * Return 0 if not exist. 786 */ 787 int sof_dai_get_bclk(struct snd_soc_pcm_runtime *rtd) 788 { 789 return sof_dai_get_clk(rtd, SOF_DAI_CLK_INTEL_SSP_BCLK); 790 } 791 EXPORT_SYMBOL(sof_dai_get_bclk); 792 793 static struct snd_sof_of_mach *sof_of_machine_select(struct snd_sof_dev *sdev) 794 { 795 struct snd_sof_pdata *sof_pdata = sdev->pdata; 796 const struct sof_dev_desc *desc = sof_pdata->desc; 797 struct snd_sof_of_mach *mach = desc->of_machines; 798 799 if (!mach) 800 return NULL; 801 802 for (; mach->compatible; mach++) { 803 if (of_machine_is_compatible(mach->compatible)) { 804 sof_pdata->tplg_filename = mach->sof_tplg_filename; 805 if (mach->fw_filename) 806 sof_pdata->fw_filename = mach->fw_filename; 807 808 return mach; 809 } 810 } 811 812 return NULL; 813 } 814 815 /* 816 * SOF Driver enumeration. 817 */ 818 int sof_machine_check(struct snd_sof_dev *sdev) 819 { 820 struct snd_sof_pdata *sof_pdata = sdev->pdata; 821 const struct sof_dev_desc *desc = sof_pdata->desc; 822 struct snd_soc_acpi_mach *mach; 823 824 if (!IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE)) { 825 const struct snd_sof_of_mach *of_mach; 826 827 /* find machine */ 828 mach = snd_sof_machine_select(sdev); 829 if (mach) { 830 sof_pdata->machine = mach; 831 snd_sof_set_mach_params(mach, sdev); 832 return 0; 833 } 834 835 of_mach = sof_of_machine_select(sdev); 836 if (of_mach) { 837 sof_pdata->of_machine = of_mach; 838 return 0; 839 } 840 841 if (!IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC)) { 842 dev_err(sdev->dev, "error: no matching ASoC machine driver found - aborting probe\n"); 843 return -ENODEV; 844 } 845 } else { 846 dev_warn(sdev->dev, "Force to use nocodec mode\n"); 847 } 848 849 /* select nocodec mode */ 850 dev_warn(sdev->dev, "Using nocodec machine driver\n"); 851 mach = devm_kzalloc(sdev->dev, sizeof(*mach), GFP_KERNEL); 852 if (!mach) 853 return -ENOMEM; 854 855 mach->drv_name = "sof-nocodec"; 856 if (!sof_pdata->tplg_filename) 857 sof_pdata->tplg_filename = desc->nocodec_tplg_filename; 858 859 sof_pdata->machine = mach; 860 snd_sof_set_mach_params(mach, sdev); 861 862 return 0; 863 } 864 EXPORT_SYMBOL(sof_machine_check); 865 866 int sof_machine_register(struct snd_sof_dev *sdev, void *pdata) 867 { 868 struct snd_sof_pdata *plat_data = pdata; 869 const char *drv_name; 870 const void *mach; 871 int size; 872 873 drv_name = plat_data->machine->drv_name; 874 mach = plat_data->machine; 875 size = sizeof(*plat_data->machine); 876 877 /* register machine driver, pass machine info as pdata */ 878 plat_data->pdev_mach = 879 platform_device_register_data(sdev->dev, drv_name, 880 PLATFORM_DEVID_NONE, mach, size); 881 if (IS_ERR(plat_data->pdev_mach)) 882 return PTR_ERR(plat_data->pdev_mach); 883 884 dev_dbg(sdev->dev, "created machine %s\n", 885 dev_name(&plat_data->pdev_mach->dev)); 886 887 return 0; 888 } 889 EXPORT_SYMBOL(sof_machine_register); 890 891 void sof_machine_unregister(struct snd_sof_dev *sdev, void *pdata) 892 { 893 struct snd_sof_pdata *plat_data = pdata; 894 895 if (!IS_ERR_OR_NULL(plat_data->pdev_mach)) 896 platform_device_unregister(plat_data->pdev_mach); 897 } 898 EXPORT_SYMBOL(sof_machine_unregister); 899