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