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) 2018 Intel Corporation. All rights reserved. 7 // 8 // Authors: Keyon Jie <yang.jie@linux.intel.com> 9 // 10 11 #include <sound/pcm_params.h> 12 #include <sound/hdaudio_ext.h> 13 #include <sound/hda-mlink.h> 14 #include <sound/hda_register.h> 15 #include <sound/intel-nhlt.h> 16 #include <sound/sof/ipc4/header.h> 17 #include <uapi/sound/sof/header.h> 18 #include "../ipc4-priv.h" 19 #include "../ipc4-topology.h" 20 #include "../sof-priv.h" 21 #include "../sof-audio.h" 22 #include "hda.h" 23 24 /* 25 * The default method is to fetch NHLT from BIOS. With this parameter set 26 * it is possible to override that with NHLT in the SOF topology manifest. 27 */ 28 static bool hda_use_tplg_nhlt; 29 module_param_named(sof_use_tplg_nhlt, hda_use_tplg_nhlt, bool, 0444); 30 MODULE_PARM_DESC(sof_use_tplg_nhlt, "SOF topology nhlt override"); 31 32 static struct snd_sof_dev *widget_to_sdev(struct snd_soc_dapm_widget *w) 33 { 34 struct snd_sof_widget *swidget = w->dobj.private; 35 struct snd_soc_component *component = swidget->scomp; 36 37 return snd_soc_component_get_drvdata(component); 38 } 39 40 int hda_dai_config(struct snd_soc_dapm_widget *w, unsigned int flags, 41 struct snd_sof_dai_config_data *data) 42 { 43 struct snd_sof_widget *swidget = w->dobj.private; 44 const struct sof_ipc_tplg_ops *tplg_ops; 45 struct snd_sof_dev *sdev; 46 int ret; 47 48 if (!swidget) 49 return 0; 50 51 sdev = widget_to_sdev(w); 52 tplg_ops = sof_ipc_get_ops(sdev, tplg); 53 54 if (tplg_ops && tplg_ops->dai_config) { 55 ret = tplg_ops->dai_config(sdev, swidget, flags, data); 56 if (ret < 0) { 57 dev_err(sdev->dev, "DAI config with flags %x failed for widget %s\n", 58 flags, w->name); 59 return ret; 60 } 61 } 62 63 return 0; 64 } 65 66 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK) 67 68 static struct snd_sof_dev *dai_to_sdev(struct snd_pcm_substream *substream, 69 struct snd_soc_dai *cpu_dai) 70 { 71 struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); 72 73 return widget_to_sdev(w); 74 } 75 76 static const struct hda_dai_widget_dma_ops * 77 hda_dai_get_ops(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) 78 { 79 struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); 80 struct snd_sof_widget *swidget = w->dobj.private; 81 struct snd_sof_dev *sdev; 82 struct snd_sof_dai *sdai; 83 84 sdev = widget_to_sdev(w); 85 86 if (!swidget) { 87 dev_err(sdev->dev, "%s: swidget is NULL\n", __func__); 88 return NULL; 89 } 90 91 if (sdev->dspless_mode_selected) 92 return hda_select_dai_widget_ops(sdev, swidget); 93 94 sdai = swidget->private; 95 96 /* select and set the DAI widget ops if not set already */ 97 if (!sdai->platform_private) { 98 const struct hda_dai_widget_dma_ops *ops = 99 hda_select_dai_widget_ops(sdev, swidget); 100 if (!ops) 101 return NULL; 102 103 /* check if mandatory ops are set */ 104 if (!ops || !ops->get_hext_stream) 105 return NULL; 106 107 sdai->platform_private = ops; 108 } 109 110 return sdai->platform_private; 111 } 112 113 int hda_link_dma_cleanup(struct snd_pcm_substream *substream, struct hdac_ext_stream *hext_stream, 114 struct snd_soc_dai *cpu_dai) 115 { 116 const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai); 117 struct sof_intel_hda_stream *hda_stream; 118 struct hdac_ext_link *hlink; 119 struct snd_sof_dev *sdev; 120 int stream_tag; 121 122 if (!ops) { 123 dev_err(cpu_dai->dev, "DAI widget ops not set\n"); 124 return -EINVAL; 125 } 126 127 sdev = dai_to_sdev(substream, cpu_dai); 128 129 hlink = ops->get_hlink(sdev, substream); 130 if (!hlink) 131 return -EINVAL; 132 133 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 134 stream_tag = hdac_stream(hext_stream)->stream_tag; 135 snd_hdac_ext_bus_link_clear_stream_id(hlink, stream_tag); 136 } 137 138 if (ops->release_hext_stream) 139 ops->release_hext_stream(sdev, cpu_dai, substream); 140 141 hext_stream->link_prepared = 0; 142 143 /* free the host DMA channel reserved by hostless streams */ 144 hda_stream = hstream_to_sof_hda_stream(hext_stream); 145 hda_stream->host_reserved = 0; 146 147 return 0; 148 } 149 150 static int hda_link_dma_hw_params(struct snd_pcm_substream *substream, 151 struct snd_pcm_hw_params *params, struct snd_soc_dai *cpu_dai) 152 { 153 const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai); 154 struct hdac_ext_stream *hext_stream; 155 struct hdac_stream *hstream; 156 struct hdac_ext_link *hlink; 157 struct snd_sof_dev *sdev; 158 int stream_tag; 159 160 if (!ops) { 161 dev_err(cpu_dai->dev, "DAI widget ops not set\n"); 162 return -EINVAL; 163 } 164 165 sdev = dai_to_sdev(substream, cpu_dai); 166 167 hlink = ops->get_hlink(sdev, substream); 168 if (!hlink) 169 return -EINVAL; 170 171 hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream); 172 173 if (!hext_stream) { 174 if (ops->assign_hext_stream) 175 hext_stream = ops->assign_hext_stream(sdev, cpu_dai, substream); 176 } 177 178 if (!hext_stream) 179 return -EBUSY; 180 181 hstream = &hext_stream->hstream; 182 stream_tag = hstream->stream_tag; 183 184 if (hext_stream->hstream.direction == SNDRV_PCM_STREAM_PLAYBACK) 185 snd_hdac_ext_bus_link_set_stream_id(hlink, stream_tag); 186 187 /* set the hdac_stream in the codec dai */ 188 if (ops->codec_dai_set_stream) 189 ops->codec_dai_set_stream(sdev, substream, hstream); 190 191 if (ops->reset_hext_stream) 192 ops->reset_hext_stream(sdev, hext_stream); 193 194 if (ops->calc_stream_format && ops->setup_hext_stream) { 195 unsigned int format_val = ops->calc_stream_format(sdev, substream, params); 196 197 ops->setup_hext_stream(sdev, hext_stream, format_val); 198 } 199 200 hext_stream->link_prepared = 1; 201 202 return 0; 203 } 204 205 static int __maybe_unused hda_dai_hw_free(struct snd_pcm_substream *substream, 206 struct snd_soc_dai *cpu_dai) 207 { 208 const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai); 209 struct hdac_ext_stream *hext_stream; 210 struct snd_sof_dev *sdev = dai_to_sdev(substream, cpu_dai); 211 212 if (!ops) { 213 dev_err(cpu_dai->dev, "DAI widget ops not set\n"); 214 return -EINVAL; 215 } 216 217 hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream); 218 if (!hext_stream) 219 return 0; 220 221 return hda_link_dma_cleanup(substream, hext_stream, cpu_dai); 222 } 223 224 static int __maybe_unused hda_dai_hw_params(struct snd_pcm_substream *substream, 225 struct snd_pcm_hw_params *params, 226 struct snd_soc_dai *dai) 227 { 228 struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, substream->stream); 229 const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai); 230 struct hdac_ext_stream *hext_stream; 231 struct snd_sof_dai_config_data data = { 0 }; 232 unsigned int flags = SOF_DAI_CONFIG_FLAGS_HW_PARAMS; 233 struct snd_sof_dev *sdev = widget_to_sdev(w); 234 int ret; 235 236 if (!ops) { 237 dev_err(sdev->dev, "DAI widget ops not set\n"); 238 return -EINVAL; 239 } 240 241 hext_stream = ops->get_hext_stream(sdev, dai, substream); 242 if (hext_stream && hext_stream->link_prepared) 243 return 0; 244 245 ret = hda_link_dma_hw_params(substream, params, dai); 246 if (ret < 0) 247 return ret; 248 249 hext_stream = ops->get_hext_stream(sdev, dai, substream); 250 251 flags |= SOF_DAI_CONFIG_FLAGS_2_STEP_STOP << SOF_DAI_CONFIG_FLAGS_QUIRK_SHIFT; 252 data.dai_data = hdac_stream(hext_stream)->stream_tag - 1; 253 254 return hda_dai_config(w, flags, &data); 255 } 256 257 /* 258 * In contrast to IPC3, the dai trigger in IPC4 mixes pipeline state changes 259 * (over IPC channel) and DMA state change (direct host register changes). 260 */ 261 static int __maybe_unused hda_dai_trigger(struct snd_pcm_substream *substream, int cmd, 262 struct snd_soc_dai *dai) 263 { 264 const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai); 265 struct hdac_ext_stream *hext_stream; 266 struct snd_sof_dev *sdev; 267 int ret; 268 269 if (!ops) { 270 dev_err(dai->dev, "DAI widget ops not set\n"); 271 return -EINVAL; 272 } 273 274 dev_dbg(dai->dev, "cmd=%d dai %s direction %d\n", cmd, 275 dai->name, substream->stream); 276 277 sdev = dai_to_sdev(substream, dai); 278 279 hext_stream = ops->get_hext_stream(sdev, dai, substream); 280 if (!hext_stream) 281 return -EINVAL; 282 283 if (ops->pre_trigger) { 284 ret = ops->pre_trigger(sdev, dai, substream, cmd); 285 if (ret < 0) 286 return ret; 287 } 288 289 if (ops->trigger) { 290 ret = ops->trigger(sdev, dai, substream, cmd); 291 if (ret < 0) 292 return ret; 293 } 294 295 if (ops->post_trigger) { 296 ret = ops->post_trigger(sdev, dai, substream, cmd); 297 if (ret < 0) 298 return ret; 299 } 300 301 switch (cmd) { 302 case SNDRV_PCM_TRIGGER_SUSPEND: 303 ret = hda_link_dma_cleanup(substream, hext_stream, dai); 304 if (ret < 0) { 305 dev_err(sdev->dev, "%s: failed to clean up link DMA\n", __func__); 306 return ret; 307 } 308 break; 309 default: 310 break; 311 } 312 313 return 0; 314 } 315 316 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) 317 318 static int hda_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 319 { 320 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); 321 int stream = substream->stream; 322 323 return hda_dai_hw_params(substream, &rtd->dpcm[stream].hw_params, dai); 324 } 325 326 static const struct snd_soc_dai_ops hda_dai_ops = { 327 .hw_params = hda_dai_hw_params, 328 .hw_free = hda_dai_hw_free, 329 .trigger = hda_dai_trigger, 330 .prepare = hda_dai_prepare, 331 }; 332 333 #endif 334 335 static struct sof_ipc4_copier *widget_to_copier(struct snd_soc_dapm_widget *w) 336 { 337 struct snd_sof_widget *swidget = w->dobj.private; 338 struct snd_sof_dai *sdai = swidget->private; 339 struct sof_ipc4_copier *ipc4_copier = (struct sof_ipc4_copier *)sdai->private; 340 341 return ipc4_copier; 342 } 343 344 static int non_hda_dai_hw_params(struct snd_pcm_substream *substream, 345 struct snd_pcm_hw_params *params, 346 struct snd_soc_dai *cpu_dai) 347 { 348 struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); 349 struct sof_ipc4_dma_config_tlv *dma_config_tlv; 350 const struct hda_dai_widget_dma_ops *ops; 351 struct sof_ipc4_dma_config *dma_config; 352 struct sof_ipc4_copier *ipc4_copier; 353 struct hdac_ext_stream *hext_stream; 354 struct hdac_stream *hstream; 355 struct snd_sof_dev *sdev; 356 int stream_id; 357 int ret; 358 359 ops = hda_dai_get_ops(substream, cpu_dai); 360 if (!ops) { 361 dev_err(cpu_dai->dev, "DAI widget ops not set\n"); 362 return -EINVAL; 363 } 364 365 /* use HDaudio stream handling */ 366 ret = hda_dai_hw_params(substream, params, cpu_dai); 367 if (ret < 0) { 368 dev_err(cpu_dai->dev, "%s: hda_dai_hw_params failed: %d\n", __func__, ret); 369 return ret; 370 } 371 372 sdev = widget_to_sdev(w); 373 if (sdev->dspless_mode_selected) 374 goto skip_tlv; 375 376 /* get stream_id */ 377 hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream); 378 379 if (!hext_stream) { 380 dev_err(cpu_dai->dev, "%s: no hext_stream found\n", __func__); 381 return -ENODEV; 382 } 383 384 hstream = &hext_stream->hstream; 385 stream_id = hstream->stream_tag; 386 387 if (!stream_id) { 388 dev_err(cpu_dai->dev, "%s: no stream_id allocated\n", __func__); 389 return -ENODEV; 390 } 391 392 /* configure TLV */ 393 ipc4_copier = widget_to_copier(w); 394 395 dma_config_tlv = &ipc4_copier->dma_config_tlv; 396 dma_config_tlv->type = SOF_IPC4_GTW_DMA_CONFIG_ID; 397 /* dma_config_priv_size is zero */ 398 dma_config_tlv->length = sizeof(dma_config_tlv->dma_config); 399 400 dma_config = &dma_config_tlv->dma_config; 401 402 dma_config->dma_method = SOF_IPC4_DMA_METHOD_HDA; 403 dma_config->pre_allocated_by_host = 1; 404 dma_config->dma_channel_id = stream_id - 1; 405 dma_config->stream_id = stream_id; 406 dma_config->dma_stream_channel_map.device_count = 0; /* mapping not used */ 407 dma_config->dma_priv_config_size = 0; 408 409 skip_tlv: 410 return 0; 411 } 412 413 static int non_hda_dai_prepare(struct snd_pcm_substream *substream, 414 struct snd_soc_dai *cpu_dai) 415 { 416 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); 417 int stream = substream->stream; 418 419 return non_hda_dai_hw_params(substream, &rtd->dpcm[stream].hw_params, cpu_dai); 420 } 421 422 static const struct snd_soc_dai_ops ssp_dai_ops = { 423 .hw_params = non_hda_dai_hw_params, 424 .hw_free = hda_dai_hw_free, 425 .trigger = hda_dai_trigger, 426 .prepare = non_hda_dai_prepare, 427 }; 428 429 static const struct snd_soc_dai_ops dmic_dai_ops = { 430 .hw_params = non_hda_dai_hw_params, 431 .hw_free = hda_dai_hw_free, 432 .trigger = hda_dai_trigger, 433 .prepare = non_hda_dai_prepare, 434 }; 435 436 int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream, 437 struct snd_pcm_hw_params *params, 438 struct snd_soc_dai *cpu_dai, 439 int link_id) 440 { 441 struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); 442 const struct hda_dai_widget_dma_ops *ops; 443 struct hdac_ext_stream *hext_stream; 444 struct snd_sof_dev *sdev; 445 int ret; 446 447 ret = non_hda_dai_hw_params(substream, params, cpu_dai); 448 if (ret < 0) { 449 dev_err(cpu_dai->dev, "%s: non_hda_dai_hw_params failed %d\n", __func__, ret); 450 return ret; 451 } 452 453 ops = hda_dai_get_ops(substream, cpu_dai); 454 sdev = widget_to_sdev(w); 455 hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream); 456 457 if (!hext_stream) 458 return -ENODEV; 459 460 /* in the case of SoundWire we need to program the PCMSyCM registers */ 461 ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id, cpu_dai->id, 462 GENMASK(params_channels(params) - 1, 0), 463 hdac_stream(hext_stream)->stream_tag, 464 substream->stream); 465 if (ret < 0) { 466 dev_err(cpu_dai->dev, "%s: hdac_bus_eml_sdw_map_stream_ch failed %d\n", 467 __func__, ret); 468 return ret; 469 } 470 471 return 0; 472 } 473 474 int sdw_hda_dai_hw_free(struct snd_pcm_substream *substream, 475 struct snd_soc_dai *cpu_dai, 476 int link_id) 477 { 478 struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); 479 struct snd_sof_dev *sdev; 480 int ret; 481 482 ret = hda_dai_hw_free(substream, cpu_dai); 483 if (ret < 0) { 484 dev_err(cpu_dai->dev, "%s: non_hda_dai_hw_free failed %d\n", __func__, ret); 485 return ret; 486 } 487 488 sdev = widget_to_sdev(w); 489 490 /* in the case of SoundWire we need to reset the PCMSyCM registers */ 491 ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id, cpu_dai->id, 492 0, 0, substream->stream); 493 if (ret < 0) { 494 dev_err(cpu_dai->dev, "%s: hdac_bus_eml_sdw_map_stream_ch failed %d\n", 495 __func__, ret); 496 return ret; 497 } 498 499 return 0; 500 } 501 502 int sdw_hda_dai_trigger(struct snd_pcm_substream *substream, int cmd, 503 struct snd_soc_dai *cpu_dai) 504 { 505 return hda_dai_trigger(substream, cmd, cpu_dai); 506 } 507 508 static int hda_dai_suspend(struct hdac_bus *bus) 509 { 510 struct snd_soc_pcm_runtime *rtd; 511 struct hdac_ext_stream *hext_stream; 512 struct hdac_stream *s; 513 int ret; 514 515 /* set internal flag for BE */ 516 list_for_each_entry(s, &bus->stream_list, list) { 517 518 hext_stream = stream_to_hdac_ext_stream(s); 519 520 /* 521 * clear stream. This should already be taken care for running 522 * streams when the SUSPEND trigger is called. But paused 523 * streams do not get suspended, so this needs to be done 524 * explicitly during suspend. 525 */ 526 if (hext_stream->link_substream) { 527 const struct hda_dai_widget_dma_ops *ops; 528 struct snd_sof_widget *swidget; 529 struct snd_soc_dapm_widget *w; 530 struct snd_soc_dai *cpu_dai; 531 struct snd_sof_dev *sdev; 532 struct snd_sof_dai *sdai; 533 534 rtd = snd_soc_substream_to_rtd(hext_stream->link_substream); 535 cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); 536 w = snd_soc_dai_get_widget(cpu_dai, hdac_stream(hext_stream)->direction); 537 swidget = w->dobj.private; 538 sdev = widget_to_sdev(w); 539 sdai = swidget->private; 540 ops = sdai->platform_private; 541 542 ret = hda_link_dma_cleanup(hext_stream->link_substream, 543 hext_stream, 544 cpu_dai); 545 if (ret < 0) 546 return ret; 547 548 /* for consistency with TRIGGER_SUSPEND */ 549 if (ops->post_trigger) { 550 ret = ops->post_trigger(sdev, cpu_dai, 551 hext_stream->link_substream, 552 SNDRV_PCM_TRIGGER_SUSPEND); 553 if (ret < 0) 554 return ret; 555 } 556 } 557 } 558 559 return 0; 560 } 561 562 static void ssp_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) 563 { 564 const struct sof_intel_dsp_desc *chip; 565 int i; 566 567 chip = get_chip_info(sdev->pdata); 568 569 if (chip->hw_ip_version >= SOF_INTEL_ACE_2_0) { 570 for (i = 0; i < ops->num_drv; i++) { 571 if (strstr(ops->drv[i].name, "SSP")) 572 ops->drv[i].ops = &ssp_dai_ops; 573 } 574 } 575 } 576 577 static void dmic_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) 578 { 579 const struct sof_intel_dsp_desc *chip; 580 int i; 581 582 chip = get_chip_info(sdev->pdata); 583 584 if (chip->hw_ip_version >= SOF_INTEL_ACE_2_0) { 585 for (i = 0; i < ops->num_drv; i++) { 586 if (strstr(ops->drv[i].name, "DMIC")) 587 ops->drv[i].ops = &dmic_dai_ops; 588 } 589 } 590 } 591 592 #else 593 594 static inline void ssp_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) {} 595 static inline void dmic_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) {} 596 597 #endif /* CONFIG_SND_SOC_SOF_HDA_LINK */ 598 599 void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) 600 { 601 int i; 602 603 for (i = 0; i < ops->num_drv; i++) { 604 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) 605 if (strstr(ops->drv[i].name, "iDisp") || 606 strstr(ops->drv[i].name, "Analog") || 607 strstr(ops->drv[i].name, "Digital")) 608 ops->drv[i].ops = &hda_dai_ops; 609 #endif 610 } 611 612 ssp_set_dai_drv_ops(sdev, ops); 613 dmic_set_dai_drv_ops(sdev, ops); 614 615 if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4 && !hda_use_tplg_nhlt) { 616 struct sof_ipc4_fw_data *ipc4_data = sdev->private; 617 618 ipc4_data->nhlt = intel_nhlt_init(sdev->dev); 619 } 620 } 621 622 void hda_ops_free(struct snd_sof_dev *sdev) 623 { 624 if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) { 625 struct sof_ipc4_fw_data *ipc4_data = sdev->private; 626 627 if (!hda_use_tplg_nhlt) 628 intel_nhlt_free(ipc4_data->nhlt); 629 630 kfree(sdev->private); 631 sdev->private = NULL; 632 } 633 } 634 EXPORT_SYMBOL_NS(hda_ops_free, SND_SOC_SOF_INTEL_HDA_COMMON); 635 636 /* 637 * common dai driver for skl+ platforms. 638 * some products who use this DAI array only physically have a subset of 639 * the DAIs, but no harm is done here by adding the whole set. 640 */ 641 struct snd_soc_dai_driver skl_dai[] = { 642 { 643 .name = "SSP0 Pin", 644 .playback = { 645 .channels_min = 1, 646 .channels_max = 8, 647 }, 648 .capture = { 649 .channels_min = 1, 650 .channels_max = 8, 651 }, 652 }, 653 { 654 .name = "SSP1 Pin", 655 .playback = { 656 .channels_min = 1, 657 .channels_max = 8, 658 }, 659 .capture = { 660 .channels_min = 1, 661 .channels_max = 8, 662 }, 663 }, 664 { 665 .name = "SSP2 Pin", 666 .playback = { 667 .channels_min = 1, 668 .channels_max = 8, 669 }, 670 .capture = { 671 .channels_min = 1, 672 .channels_max = 8, 673 }, 674 }, 675 { 676 .name = "SSP3 Pin", 677 .playback = { 678 .channels_min = 1, 679 .channels_max = 8, 680 }, 681 .capture = { 682 .channels_min = 1, 683 .channels_max = 8, 684 }, 685 }, 686 { 687 .name = "SSP4 Pin", 688 .playback = { 689 .channels_min = 1, 690 .channels_max = 8, 691 }, 692 .capture = { 693 .channels_min = 1, 694 .channels_max = 8, 695 }, 696 }, 697 { 698 .name = "SSP5 Pin", 699 .playback = { 700 .channels_min = 1, 701 .channels_max = 8, 702 }, 703 .capture = { 704 .channels_min = 1, 705 .channels_max = 8, 706 }, 707 }, 708 { 709 .name = "DMIC01 Pin", 710 .capture = { 711 .channels_min = 1, 712 .channels_max = 4, 713 }, 714 }, 715 { 716 .name = "DMIC16k Pin", 717 .capture = { 718 .channels_min = 1, 719 .channels_max = 4, 720 }, 721 }, 722 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) 723 { 724 .name = "iDisp1 Pin", 725 .playback = { 726 .channels_min = 1, 727 .channels_max = 8, 728 }, 729 }, 730 { 731 .name = "iDisp2 Pin", 732 .playback = { 733 .channels_min = 1, 734 .channels_max = 8, 735 }, 736 }, 737 { 738 .name = "iDisp3 Pin", 739 .playback = { 740 .channels_min = 1, 741 .channels_max = 8, 742 }, 743 }, 744 { 745 .name = "iDisp4 Pin", 746 .playback = { 747 .channels_min = 1, 748 .channels_max = 8, 749 }, 750 }, 751 { 752 .name = "Analog CPU DAI", 753 .playback = { 754 .channels_min = 1, 755 .channels_max = 16, 756 }, 757 .capture = { 758 .channels_min = 1, 759 .channels_max = 16, 760 }, 761 }, 762 { 763 .name = "Digital CPU DAI", 764 .playback = { 765 .channels_min = 1, 766 .channels_max = 16, 767 }, 768 .capture = { 769 .channels_min = 1, 770 .channels_max = 16, 771 }, 772 }, 773 { 774 .name = "Alt Analog CPU DAI", 775 .playback = { 776 .channels_min = 1, 777 .channels_max = 16, 778 }, 779 .capture = { 780 .channels_min = 1, 781 .channels_max = 16, 782 }, 783 }, 784 #endif 785 }; 786 787 int hda_dsp_dais_suspend(struct snd_sof_dev *sdev) 788 { 789 /* 790 * In the corner case where a SUSPEND happens during a PAUSE, the ALSA core 791 * does not throw the TRIGGER_SUSPEND. This leaves the DAIs in an unbalanced state. 792 * Since the component suspend is called last, we can trap this corner case 793 * and force the DAIs to release their resources. 794 */ 795 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK) 796 int ret; 797 798 ret = hda_dai_suspend(sof_to_bus(sdev)); 799 if (ret < 0) 800 return ret; 801 #endif 802 803 return 0; 804 } 805