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 "ops.h" 14 15 static int sof_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol) 16 { 17 int ipc_cmd, ctrl_type; 18 int ret; 19 20 /* reset readback offset for scontrol */ 21 scontrol->readback_offset = 0; 22 23 /* notify DSP of kcontrol values */ 24 switch (scontrol->cmd) { 25 case SOF_CTRL_CMD_VOLUME: 26 case SOF_CTRL_CMD_ENUM: 27 case SOF_CTRL_CMD_SWITCH: 28 ipc_cmd = SOF_IPC_COMP_SET_VALUE; 29 ctrl_type = SOF_CTRL_TYPE_VALUE_CHAN_SET; 30 break; 31 case SOF_CTRL_CMD_BINARY: 32 ipc_cmd = SOF_IPC_COMP_SET_DATA; 33 ctrl_type = SOF_CTRL_TYPE_DATA_SET; 34 break; 35 default: 36 return 0; 37 } 38 39 ret = snd_sof_ipc_set_get_comp_data(scontrol, ipc_cmd, ctrl_type, scontrol->cmd, true); 40 if (ret < 0) 41 dev_err(sdev->dev, "error: failed kcontrol value set for widget: %d\n", 42 scontrol->comp_id); 43 44 return ret; 45 } 46 47 static int sof_dai_config_setup(struct snd_sof_dev *sdev, struct snd_sof_dai *dai) 48 { 49 struct sof_ipc_dai_config *config; 50 struct sof_ipc_reply reply; 51 int ret; 52 53 config = &dai->dai_config[dai->current_config]; 54 if (!config) { 55 dev_err(sdev->dev, "error: no config for DAI %s\n", dai->name); 56 return -EINVAL; 57 } 58 59 /* set NONE flag to clear all previous settings */ 60 config->flags = FIELD_PREP(SOF_DAI_CONFIG_FLAGS_MASK, SOF_DAI_CONFIG_FLAGS_NONE); 61 62 ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, config->hdr.size, 63 &reply, sizeof(reply)); 64 65 if (ret < 0) 66 dev_err(sdev->dev, "error: failed to set dai config for %s\n", dai->name); 67 68 return ret; 69 } 70 71 static int sof_widget_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) 72 { 73 struct snd_sof_control *scontrol; 74 int ret; 75 76 /* set up all controls for the widget */ 77 list_for_each_entry(scontrol, &sdev->kcontrol_list, list) 78 if (scontrol->comp_id == swidget->comp_id) { 79 ret = sof_kcontrol_setup(sdev, scontrol); 80 if (ret < 0) { 81 dev_err(sdev->dev, "error: fail to set up kcontrols for widget %s\n", 82 swidget->widget->name); 83 return ret; 84 } 85 } 86 87 return 0; 88 } 89 90 static void sof_reset_route_setup_status(struct snd_sof_dev *sdev, struct snd_sof_widget *widget) 91 { 92 struct snd_sof_route *sroute; 93 94 list_for_each_entry(sroute, &sdev->route_list, list) 95 if (sroute->src_widget == widget || sroute->sink_widget == widget) 96 sroute->setup = false; 97 } 98 99 int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) 100 { 101 struct sof_ipc_free ipc_free = { 102 .hdr = { 103 .size = sizeof(ipc_free), 104 .cmd = SOF_IPC_GLB_TPLG_MSG, 105 }, 106 .id = swidget->comp_id, 107 }; 108 struct sof_ipc_reply reply; 109 int ret; 110 111 if (!swidget->private) 112 return 0; 113 114 /* only free when use_count is 0 */ 115 if (--swidget->use_count) 116 return 0; 117 118 switch (swidget->id) { 119 case snd_soc_dapm_scheduler: 120 ipc_free.hdr.cmd |= SOF_IPC_TPLG_PIPE_FREE; 121 break; 122 case snd_soc_dapm_buffer: 123 ipc_free.hdr.cmd |= SOF_IPC_TPLG_BUFFER_FREE; 124 break; 125 default: 126 ipc_free.hdr.cmd |= SOF_IPC_TPLG_COMP_FREE; 127 break; 128 } 129 130 ret = sof_ipc_tx_message(sdev->ipc, ipc_free.hdr.cmd, &ipc_free, sizeof(ipc_free), 131 &reply, sizeof(reply)); 132 if (ret < 0) { 133 dev_err(sdev->dev, "error: failed to free widget %s\n", swidget->widget->name); 134 swidget->use_count++; 135 return ret; 136 } 137 138 /* reset route setup status for all routes that contain this widget */ 139 sof_reset_route_setup_status(sdev, swidget); 140 swidget->complete = 0; 141 dev_dbg(sdev->dev, "widget %s freed\n", swidget->widget->name); 142 143 return 0; 144 } 145 EXPORT_SYMBOL(sof_widget_free); 146 147 int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) 148 { 149 struct sof_ipc_pipe_new *pipeline; 150 struct sof_ipc_comp_reply r; 151 struct sof_ipc_cmd_hdr *hdr; 152 struct sof_ipc_comp *comp; 153 struct snd_sof_dai *dai; 154 size_t ipc_size; 155 int ret; 156 157 /* skip if there is no private data */ 158 if (!swidget->private) 159 return 0; 160 161 /* widget already set up */ 162 if (++swidget->use_count > 1) 163 return 0; 164 165 ret = sof_pipeline_core_enable(sdev, swidget); 166 if (ret < 0) { 167 dev_err(sdev->dev, "error: failed to enable target core: %d for widget %s\n", 168 ret, swidget->widget->name); 169 goto use_count_dec; 170 } 171 172 switch (swidget->id) { 173 case snd_soc_dapm_dai_in: 174 case snd_soc_dapm_dai_out: 175 ipc_size = sizeof(struct sof_ipc_comp_dai) + sizeof(struct sof_ipc_comp_ext); 176 comp = kzalloc(ipc_size, GFP_KERNEL); 177 if (!comp) 178 return -ENOMEM; 179 180 dai = swidget->private; 181 dai->configured = false; 182 memcpy(comp, &dai->comp_dai, sizeof(struct sof_ipc_comp_dai)); 183 184 /* append extended data to the end of the component */ 185 memcpy((u8 *)comp + sizeof(struct sof_ipc_comp_dai), &swidget->comp_ext, 186 sizeof(swidget->comp_ext)); 187 188 ret = sof_ipc_tx_message(sdev->ipc, comp->hdr.cmd, comp, ipc_size, &r, sizeof(r)); 189 kfree(comp); 190 if (ret < 0) { 191 dev_err(sdev->dev, "error: failed to load widget %s\n", 192 swidget->widget->name); 193 goto use_count_dec; 194 } 195 196 ret = sof_dai_config_setup(sdev, dai); 197 if (ret < 0) { 198 dev_err(sdev->dev, "error: failed to load dai config for DAI %s\n", 199 swidget->widget->name); 200 sof_widget_free(sdev, swidget); 201 return ret; 202 } 203 break; 204 case snd_soc_dapm_scheduler: 205 pipeline = swidget->private; 206 ret = sof_load_pipeline_ipc(sdev, pipeline, &r); 207 break; 208 default: 209 hdr = swidget->private; 210 ret = sof_ipc_tx_message(sdev->ipc, hdr->cmd, swidget->private, hdr->size, 211 &r, sizeof(r)); 212 break; 213 } 214 if (ret < 0) { 215 dev_err(sdev->dev, "error: failed to load widget %s\n", swidget->widget->name); 216 goto use_count_dec; 217 } 218 219 /* restore kcontrols for widget */ 220 ret = sof_widget_kcontrol_setup(sdev, swidget); 221 if (ret < 0) { 222 dev_err(sdev->dev, "error: failed to restore kcontrols for widget %s\n", 223 swidget->widget->name); 224 sof_widget_free(sdev, swidget); 225 return ret; 226 } 227 228 dev_dbg(sdev->dev, "widget %s setup complete\n", swidget->widget->name); 229 230 return 0; 231 232 use_count_dec: 233 swidget->use_count--; 234 return ret; 235 } 236 EXPORT_SYMBOL(sof_widget_setup); 237 238 static int sof_route_setup_ipc(struct snd_sof_dev *sdev, struct snd_sof_route *sroute) 239 { 240 struct sof_ipc_pipe_comp_connect *connect; 241 struct sof_ipc_reply reply; 242 int ret; 243 244 /* skip if there's no private data */ 245 if (!sroute->private) 246 return 0; 247 248 /* nothing to do if route is already set up */ 249 if (sroute->setup) 250 return 0; 251 252 connect = sroute->private; 253 254 dev_dbg(sdev->dev, "setting up route %s -> %s\n", 255 sroute->src_widget->widget->name, 256 sroute->sink_widget->widget->name); 257 258 /* send ipc */ 259 ret = sof_ipc_tx_message(sdev->ipc, 260 connect->hdr.cmd, 261 connect, sizeof(*connect), 262 &reply, sizeof(reply)); 263 if (ret < 0) { 264 dev_err(sdev->dev, "%s: route setup failed %d\n", __func__, ret); 265 return ret; 266 } 267 268 sroute->setup = true; 269 270 return 0; 271 } 272 273 static int sof_route_setup(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *wsource, 274 struct snd_soc_dapm_widget *wsink) 275 { 276 struct snd_sof_widget *src_widget = wsource->dobj.private; 277 struct snd_sof_widget *sink_widget = wsink->dobj.private; 278 struct snd_sof_route *sroute; 279 bool route_found = false; 280 281 /* ignore routes involving virtual widgets in topology */ 282 switch (src_widget->id) { 283 case snd_soc_dapm_out_drv: 284 case snd_soc_dapm_output: 285 case snd_soc_dapm_input: 286 return 0; 287 default: 288 break; 289 } 290 291 switch (sink_widget->id) { 292 case snd_soc_dapm_out_drv: 293 case snd_soc_dapm_output: 294 case snd_soc_dapm_input: 295 return 0; 296 default: 297 break; 298 } 299 300 /* find route matching source and sink widgets */ 301 list_for_each_entry(sroute, &sdev->route_list, list) 302 if (sroute->src_widget == src_widget && sroute->sink_widget == sink_widget) { 303 route_found = true; 304 break; 305 } 306 307 if (!route_found) { 308 dev_err(sdev->dev, "error: cannot find SOF route for source %s -> %s sink\n", 309 wsource->name, wsink->name); 310 return -EINVAL; 311 } 312 313 return sof_route_setup_ipc(sdev, sroute); 314 } 315 316 static int sof_setup_pipeline_connections(struct snd_sof_dev *sdev, 317 struct snd_soc_dapm_widget_list *list, int dir) 318 { 319 struct snd_soc_dapm_widget *widget; 320 struct snd_soc_dapm_path *p; 321 int ret; 322 int i; 323 324 /* 325 * Set up connections between widgets in the sink/source paths based on direction. 326 * Some non-SOF widgets exist in topology either for compatibility or for the 327 * purpose of connecting a pipeline from a host to a DAI in order to receive the DAPM 328 * events. But they are not handled by the firmware. So ignore them. 329 */ 330 if (dir == SNDRV_PCM_STREAM_PLAYBACK) { 331 for_each_dapm_widgets(list, i, widget) { 332 if (!widget->dobj.private) 333 continue; 334 335 snd_soc_dapm_widget_for_each_sink_path(widget, p) 336 if (p->sink->dobj.private) { 337 ret = sof_route_setup(sdev, widget, p->sink); 338 if (ret < 0) 339 return ret; 340 } 341 } 342 } else { 343 for_each_dapm_widgets(list, i, widget) { 344 if (!widget->dobj.private) 345 continue; 346 347 snd_soc_dapm_widget_for_each_source_path(widget, p) 348 if (p->source->dobj.private) { 349 ret = sof_route_setup(sdev, p->source, widget); 350 if (ret < 0) 351 return ret; 352 } 353 } 354 } 355 356 return 0; 357 } 358 359 int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int dir) 360 { 361 struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list; 362 struct snd_soc_dapm_widget *widget; 363 int i, ret, num_widgets; 364 365 /* nothing to set up */ 366 if (!list) 367 return 0; 368 369 /* set up widgets in the list */ 370 for_each_dapm_widgets(list, num_widgets, widget) { 371 struct snd_sof_widget *swidget = widget->dobj.private; 372 struct snd_sof_widget *pipe_widget; 373 374 if (!swidget) 375 continue; 376 377 /* 378 * The scheduler widget for a pipeline is not part of the connected DAPM 379 * widget list and it needs to be set up before the widgets in the pipeline 380 * are set up. The use_count for the scheduler widget is incremented for every 381 * widget in a given pipeline to ensure that it is freed only after the last 382 * widget in the pipeline is freed. 383 */ 384 pipe_widget = swidget->pipe_widget; 385 if (!pipe_widget) { 386 dev_err(sdev->dev, "error: no pipeline widget found for %s\n", 387 swidget->widget->name); 388 ret = -EINVAL; 389 goto widget_free; 390 } 391 392 ret = sof_widget_setup(sdev, pipe_widget); 393 if (ret < 0) 394 goto widget_free; 395 396 /* set up the widget */ 397 ret = sof_widget_setup(sdev, swidget); 398 if (ret < 0) { 399 sof_widget_free(sdev, pipe_widget); 400 goto widget_free; 401 } 402 } 403 404 /* 405 * error in setting pipeline connections will result in route status being reset for 406 * routes that were successfully set up when the widgets are freed. 407 */ 408 ret = sof_setup_pipeline_connections(sdev, list, dir); 409 if (ret < 0) 410 goto widget_free; 411 412 /* complete pipelines */ 413 for_each_dapm_widgets(list, i, widget) { 414 struct snd_sof_widget *swidget = widget->dobj.private; 415 struct snd_sof_widget *pipe_widget; 416 417 if (!swidget) 418 continue; 419 420 pipe_widget = swidget->pipe_widget; 421 if (!pipe_widget) { 422 dev_err(sdev->dev, "error: no pipeline widget found for %s\n", 423 swidget->widget->name); 424 ret = -EINVAL; 425 goto widget_free; 426 } 427 428 if (pipe_widget->complete) 429 continue; 430 431 pipe_widget->complete = snd_sof_complete_pipeline(sdev, pipe_widget); 432 if (pipe_widget->complete < 0) { 433 ret = pipe_widget->complete; 434 goto widget_free; 435 } 436 } 437 438 return 0; 439 440 widget_free: 441 /* free all widgets that have been set up successfully */ 442 for_each_dapm_widgets(list, i, widget) { 443 struct snd_sof_widget *swidget = widget->dobj.private; 444 445 if (!swidget) 446 continue; 447 448 if (!num_widgets--) 449 break; 450 451 sof_widget_free(sdev, swidget); 452 sof_widget_free(sdev, swidget->pipe_widget); 453 } 454 455 return ret; 456 } 457 458 int sof_widget_list_free(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int dir) 459 { 460 struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list; 461 struct snd_soc_dapm_widget *widget; 462 int i, ret; 463 int ret1 = 0; 464 465 /* nothing to free */ 466 if (!list) 467 return 0; 468 469 /* 470 * Free widgets in the list. This can fail but continue freeing other widgets to keep 471 * use_counts balanced. 472 */ 473 for_each_dapm_widgets(list, i, widget) { 474 struct snd_sof_widget *swidget = widget->dobj.private; 475 476 if (!swidget) 477 continue; 478 479 /* 480 * free widget and its pipe_widget. Either of these can fail, but free as many as 481 * possible before freeing the list and returning the error. 482 */ 483 ret = sof_widget_free(sdev, swidget); 484 if (ret < 0) 485 ret1 = ret; 486 487 ret = sof_widget_free(sdev, swidget->pipe_widget); 488 if (ret < 0) 489 ret1 = ret; 490 } 491 492 snd_soc_dapm_dai_free_widgets(&list); 493 spcm->stream[dir].list = NULL; 494 495 return ret1; 496 } 497 498 /* 499 * helper to determine if there are only D0i3 compatible 500 * streams active 501 */ 502 bool snd_sof_dsp_only_d0i3_compatible_stream_active(struct snd_sof_dev *sdev) 503 { 504 struct snd_pcm_substream *substream; 505 struct snd_sof_pcm *spcm; 506 bool d0i3_compatible_active = false; 507 int dir; 508 509 list_for_each_entry(spcm, &sdev->pcm_list, list) { 510 for_each_pcm_streams(dir) { 511 substream = spcm->stream[dir].substream; 512 if (!substream || !substream->runtime) 513 continue; 514 515 /* 516 * substream->runtime being not NULL indicates 517 * that the stream is open. No need to check the 518 * stream state. 519 */ 520 if (!spcm->stream[dir].d0i3_compatible) 521 return false; 522 523 d0i3_compatible_active = true; 524 } 525 } 526 527 return d0i3_compatible_active; 528 } 529 EXPORT_SYMBOL(snd_sof_dsp_only_d0i3_compatible_stream_active); 530 531 bool snd_sof_stream_suspend_ignored(struct snd_sof_dev *sdev) 532 { 533 struct snd_sof_pcm *spcm; 534 535 list_for_each_entry(spcm, &sdev->pcm_list, list) { 536 if (spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].suspend_ignored || 537 spcm->stream[SNDRV_PCM_STREAM_CAPTURE].suspend_ignored) 538 return true; 539 } 540 541 return false; 542 } 543 544 int sof_set_hw_params_upon_resume(struct device *dev) 545 { 546 struct snd_sof_dev *sdev = dev_get_drvdata(dev); 547 struct snd_pcm_substream *substream; 548 struct snd_sof_pcm *spcm; 549 snd_pcm_state_t state; 550 int dir; 551 552 /* 553 * SOF requires hw_params to be set-up internally upon resume. 554 * So, set the flag to indicate this for those streams that 555 * have been suspended. 556 */ 557 list_for_each_entry(spcm, &sdev->pcm_list, list) { 558 for_each_pcm_streams(dir) { 559 /* 560 * do not reset hw_params upon resume for streams that 561 * were kept running during suspend 562 */ 563 if (spcm->stream[dir].suspend_ignored) 564 continue; 565 566 substream = spcm->stream[dir].substream; 567 if (!substream || !substream->runtime) 568 continue; 569 570 state = substream->runtime->status->state; 571 if (state == SNDRV_PCM_STATE_SUSPENDED) 572 spcm->prepared[dir] = false; 573 } 574 } 575 576 /* set internal flag for BE */ 577 return snd_sof_dsp_hw_params_upon_resume(sdev); 578 } 579 580 const struct sof_ipc_pipe_new *snd_sof_pipeline_find(struct snd_sof_dev *sdev, 581 int pipeline_id) 582 { 583 const struct snd_sof_widget *swidget; 584 585 list_for_each_entry(swidget, &sdev->widget_list, list) 586 if (swidget->id == snd_soc_dapm_scheduler) { 587 const struct sof_ipc_pipe_new *pipeline = 588 swidget->private; 589 if (pipeline->pipeline_id == pipeline_id) 590 return pipeline; 591 } 592 593 return NULL; 594 } 595 596 int sof_set_up_pipelines(struct snd_sof_dev *sdev, bool verify) 597 { 598 struct snd_sof_widget *swidget; 599 struct snd_sof_route *sroute; 600 int ret; 601 602 /* restore pipeline components */ 603 list_for_each_entry_reverse(swidget, &sdev->widget_list, list) { 604 /* only set up the widgets belonging to static pipelines */ 605 if (!verify && swidget->dynamic_pipeline_widget) 606 continue; 607 608 /* update DAI config. The IPC will be sent in sof_widget_setup() */ 609 if (WIDGET_IS_DAI(swidget->id)) { 610 struct snd_sof_dai *dai = swidget->private; 611 struct sof_ipc_dai_config *config; 612 613 if (!dai || !dai->dai_config) 614 continue; 615 616 config = dai->dai_config; 617 /* 618 * The link DMA channel would be invalidated for running 619 * streams but not for streams that were in the PAUSED 620 * state during suspend. So invalidate it here before setting 621 * the dai config in the DSP. 622 */ 623 if (config->type == SOF_DAI_INTEL_HDA) 624 config->hda.link_dma_ch = DMA_CHAN_INVALID; 625 } 626 627 ret = sof_widget_setup(sdev, swidget); 628 if (ret < 0) 629 return ret; 630 } 631 632 /* restore pipeline connections */ 633 list_for_each_entry(sroute, &sdev->route_list, list) { 634 635 /* only set up routes belonging to static pipelines */ 636 if (!verify && (sroute->src_widget->dynamic_pipeline_widget || 637 sroute->sink_widget->dynamic_pipeline_widget)) 638 continue; 639 640 ret = sof_route_setup_ipc(sdev, sroute); 641 if (ret < 0) { 642 dev_err(sdev->dev, "%s: restore pipeline connections failed\n", __func__); 643 return ret; 644 } 645 } 646 647 /* complete pipeline */ 648 list_for_each_entry(swidget, &sdev->widget_list, list) { 649 switch (swidget->id) { 650 case snd_soc_dapm_scheduler: 651 /* only complete static pipelines */ 652 if (!verify && swidget->dynamic_pipeline_widget) 653 continue; 654 655 swidget->complete = 656 snd_sof_complete_pipeline(sdev, swidget); 657 break; 658 default: 659 break; 660 } 661 } 662 663 return 0; 664 } 665 666 /* 667 * This function doesn't free widgets during suspend. It only resets the set up status for all 668 * routes and use_count for all widgets. 669 */ 670 int sof_tear_down_pipelines(struct snd_sof_dev *sdev, bool verify) 671 { 672 struct snd_sof_widget *swidget; 673 struct snd_sof_route *sroute; 674 int ret; 675 676 /* 677 * This function is called during suspend and for one-time topology verification during 678 * first boot. In both cases, there is no need to protect swidget->use_count and 679 * sroute->setup because during suspend all streams are suspended and during topology 680 * loading the sound card unavailable to open PCMs. 681 */ 682 list_for_each_entry_reverse(swidget, &sdev->widget_list, list) { 683 if (!verify) { 684 swidget->use_count = 0; 685 continue; 686 } 687 688 ret = sof_widget_free(sdev, swidget); 689 if (ret < 0) 690 return ret; 691 } 692 693 list_for_each_entry(sroute, &sdev->route_list, list) 694 sroute->setup = false; 695 696 return 0; 697 } 698 699 /* 700 * Generic object lookup APIs. 701 */ 702 703 struct snd_sof_pcm *snd_sof_find_spcm_name(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_pcm *spcm; 708 709 list_for_each_entry(spcm, &sdev->pcm_list, list) { 710 /* match with PCM dai name */ 711 if (strcmp(spcm->pcm.dai_name, name) == 0) 712 return spcm; 713 714 /* match with playback caps name if set */ 715 if (*spcm->pcm.caps[0].name && 716 !strcmp(spcm->pcm.caps[0].name, name)) 717 return spcm; 718 719 /* match with capture caps name if set */ 720 if (*spcm->pcm.caps[1].name && 721 !strcmp(spcm->pcm.caps[1].name, name)) 722 return spcm; 723 } 724 725 return NULL; 726 } 727 728 struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_soc_component *scomp, 729 unsigned int comp_id, 730 int *direction) 731 { 732 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 733 struct snd_sof_pcm *spcm; 734 int dir; 735 736 list_for_each_entry(spcm, &sdev->pcm_list, list) { 737 for_each_pcm_streams(dir) { 738 if (spcm->stream[dir].comp_id == comp_id) { 739 *direction = dir; 740 return spcm; 741 } 742 } 743 } 744 745 return NULL; 746 } 747 748 struct snd_sof_pcm *snd_sof_find_spcm_pcm_id(struct snd_soc_component *scomp, 749 unsigned int pcm_id) 750 { 751 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 752 struct snd_sof_pcm *spcm; 753 754 list_for_each_entry(spcm, &sdev->pcm_list, list) { 755 if (le32_to_cpu(spcm->pcm.pcm_id) == pcm_id) 756 return spcm; 757 } 758 759 return NULL; 760 } 761 762 struct snd_sof_widget *snd_sof_find_swidget(struct snd_soc_component *scomp, 763 const char *name) 764 { 765 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 766 struct snd_sof_widget *swidget; 767 768 list_for_each_entry(swidget, &sdev->widget_list, list) { 769 if (strcmp(name, swidget->widget->name) == 0) 770 return swidget; 771 } 772 773 return NULL; 774 } 775 776 /* find widget by stream name and direction */ 777 struct snd_sof_widget * 778 snd_sof_find_swidget_sname(struct snd_soc_component *scomp, 779 const char *pcm_name, int dir) 780 { 781 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 782 struct snd_sof_widget *swidget; 783 enum snd_soc_dapm_type type; 784 785 if (dir == SNDRV_PCM_STREAM_PLAYBACK) 786 type = snd_soc_dapm_aif_in; 787 else 788 type = snd_soc_dapm_aif_out; 789 790 list_for_each_entry(swidget, &sdev->widget_list, list) { 791 if (!strcmp(pcm_name, swidget->widget->sname) && 792 swidget->id == type) 793 return swidget; 794 } 795 796 return NULL; 797 } 798 799 struct snd_sof_dai *snd_sof_find_dai(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_dai *dai; 804 805 list_for_each_entry(dai, &sdev->dai_list, list) { 806 if (dai->name && (strcmp(name, dai->name) == 0)) 807 return dai; 808 } 809 810 return NULL; 811 } 812 813 #define SOF_DAI_CLK_INTEL_SSP_MCLK 0 814 #define SOF_DAI_CLK_INTEL_SSP_BCLK 1 815 816 static int sof_dai_get_clk(struct snd_soc_pcm_runtime *rtd, int clk_type) 817 { 818 struct snd_soc_component *component = 819 snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME); 820 struct snd_sof_dai *dai = 821 snd_sof_find_dai(component, (char *)rtd->dai_link->name); 822 823 /* use the tplg configured mclk if existed */ 824 if (!dai || !dai->dai_config) 825 return 0; 826 827 switch (dai->dai_config->type) { 828 case SOF_DAI_INTEL_SSP: 829 switch (clk_type) { 830 case SOF_DAI_CLK_INTEL_SSP_MCLK: 831 return dai->dai_config->ssp.mclk_rate; 832 case SOF_DAI_CLK_INTEL_SSP_BCLK: 833 return dai->dai_config->ssp.bclk_rate; 834 default: 835 dev_err(rtd->dev, "fail to get SSP clk %d rate\n", 836 clk_type); 837 return -EINVAL; 838 } 839 break; 840 default: 841 /* not yet implemented for platforms other than the above */ 842 dev_err(rtd->dev, "DAI type %d not supported yet!\n", 843 dai->dai_config->type); 844 return -EINVAL; 845 } 846 } 847 848 /* 849 * Helper to get SSP MCLK from a pcm_runtime. 850 * Return 0 if not exist. 851 */ 852 int sof_dai_get_mclk(struct snd_soc_pcm_runtime *rtd) 853 { 854 return sof_dai_get_clk(rtd, SOF_DAI_CLK_INTEL_SSP_MCLK); 855 } 856 EXPORT_SYMBOL(sof_dai_get_mclk); 857 858 /* 859 * Helper to get SSP BCLK from a pcm_runtime. 860 * Return 0 if not exist. 861 */ 862 int sof_dai_get_bclk(struct snd_soc_pcm_runtime *rtd) 863 { 864 return sof_dai_get_clk(rtd, SOF_DAI_CLK_INTEL_SSP_BCLK); 865 } 866 EXPORT_SYMBOL(sof_dai_get_bclk); 867 868 /* 869 * SOF Driver enumeration. 870 */ 871 int sof_machine_check(struct snd_sof_dev *sdev) 872 { 873 struct snd_sof_pdata *sof_pdata = sdev->pdata; 874 const struct sof_dev_desc *desc = sof_pdata->desc; 875 struct snd_soc_acpi_mach *mach; 876 877 if (!IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE)) { 878 879 /* find machine */ 880 snd_sof_machine_select(sdev); 881 if (sof_pdata->machine) { 882 snd_sof_set_mach_params(sof_pdata->machine, sdev); 883 return 0; 884 } 885 886 if (!IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC)) { 887 dev_err(sdev->dev, "error: no matching ASoC machine driver found - aborting probe\n"); 888 return -ENODEV; 889 } 890 } else { 891 dev_warn(sdev->dev, "Force to use nocodec mode\n"); 892 } 893 894 /* select nocodec mode */ 895 dev_warn(sdev->dev, "Using nocodec machine driver\n"); 896 mach = devm_kzalloc(sdev->dev, sizeof(*mach), GFP_KERNEL); 897 if (!mach) 898 return -ENOMEM; 899 900 mach->drv_name = "sof-nocodec"; 901 sof_pdata->tplg_filename = desc->nocodec_tplg_filename; 902 903 sof_pdata->machine = mach; 904 snd_sof_set_mach_params(sof_pdata->machine, sdev); 905 906 return 0; 907 } 908 EXPORT_SYMBOL(sof_machine_check); 909 910 int sof_machine_register(struct snd_sof_dev *sdev, void *pdata) 911 { 912 struct snd_sof_pdata *plat_data = pdata; 913 const char *drv_name; 914 const void *mach; 915 int size; 916 917 drv_name = plat_data->machine->drv_name; 918 mach = plat_data->machine; 919 size = sizeof(*plat_data->machine); 920 921 /* register machine driver, pass machine info as pdata */ 922 plat_data->pdev_mach = 923 platform_device_register_data(sdev->dev, drv_name, 924 PLATFORM_DEVID_NONE, mach, size); 925 if (IS_ERR(plat_data->pdev_mach)) 926 return PTR_ERR(plat_data->pdev_mach); 927 928 dev_dbg(sdev->dev, "created machine %s\n", 929 dev_name(&plat_data->pdev_mach->dev)); 930 931 return 0; 932 } 933 EXPORT_SYMBOL(sof_machine_register); 934 935 void sof_machine_unregister(struct snd_sof_dev *sdev, void *pdata) 936 { 937 struct snd_sof_pdata *plat_data = pdata; 938 939 if (!IS_ERR_OR_NULL(plat_data->pdev_mach)) 940 platform_device_unregister(plat_data->pdev_mach); 941 } 942 EXPORT_SYMBOL(sof_machine_unregister); 943