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