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