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 } 626 EXPORT_SYMBOL_NS(hda_ops_free, SND_SOC_SOF_INTEL_HDA_COMMON); 627 628 /* 629 * common dai driver for skl+ platforms. 630 * some products who use this DAI array only physically have a subset of 631 * the DAIs, but no harm is done here by adding the whole set. 632 */ 633 struct snd_soc_dai_driver skl_dai[] = { 634 { 635 .name = "SSP0 Pin", 636 .playback = { 637 .channels_min = 1, 638 .channels_max = 8, 639 }, 640 .capture = { 641 .channels_min = 1, 642 .channels_max = 8, 643 }, 644 }, 645 { 646 .name = "SSP1 Pin", 647 .playback = { 648 .channels_min = 1, 649 .channels_max = 8, 650 }, 651 .capture = { 652 .channels_min = 1, 653 .channels_max = 8, 654 }, 655 }, 656 { 657 .name = "SSP2 Pin", 658 .playback = { 659 .channels_min = 1, 660 .channels_max = 8, 661 }, 662 .capture = { 663 .channels_min = 1, 664 .channels_max = 8, 665 }, 666 }, 667 { 668 .name = "SSP3 Pin", 669 .playback = { 670 .channels_min = 1, 671 .channels_max = 8, 672 }, 673 .capture = { 674 .channels_min = 1, 675 .channels_max = 8, 676 }, 677 }, 678 { 679 .name = "SSP4 Pin", 680 .playback = { 681 .channels_min = 1, 682 .channels_max = 8, 683 }, 684 .capture = { 685 .channels_min = 1, 686 .channels_max = 8, 687 }, 688 }, 689 { 690 .name = "SSP5 Pin", 691 .playback = { 692 .channels_min = 1, 693 .channels_max = 8, 694 }, 695 .capture = { 696 .channels_min = 1, 697 .channels_max = 8, 698 }, 699 }, 700 { 701 .name = "DMIC01 Pin", 702 .capture = { 703 .channels_min = 1, 704 .channels_max = 4, 705 }, 706 }, 707 { 708 .name = "DMIC16k Pin", 709 .capture = { 710 .channels_min = 1, 711 .channels_max = 4, 712 }, 713 }, 714 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) 715 { 716 .name = "iDisp1 Pin", 717 .playback = { 718 .channels_min = 1, 719 .channels_max = 8, 720 }, 721 }, 722 { 723 .name = "iDisp2 Pin", 724 .playback = { 725 .channels_min = 1, 726 .channels_max = 8, 727 }, 728 }, 729 { 730 .name = "iDisp3 Pin", 731 .playback = { 732 .channels_min = 1, 733 .channels_max = 8, 734 }, 735 }, 736 { 737 .name = "iDisp4 Pin", 738 .playback = { 739 .channels_min = 1, 740 .channels_max = 8, 741 }, 742 }, 743 { 744 .name = "Analog CPU DAI", 745 .playback = { 746 .channels_min = 1, 747 .channels_max = 16, 748 }, 749 .capture = { 750 .channels_min = 1, 751 .channels_max = 16, 752 }, 753 }, 754 { 755 .name = "Digital CPU DAI", 756 .playback = { 757 .channels_min = 1, 758 .channels_max = 16, 759 }, 760 .capture = { 761 .channels_min = 1, 762 .channels_max = 16, 763 }, 764 }, 765 { 766 .name = "Alt Analog CPU DAI", 767 .playback = { 768 .channels_min = 1, 769 .channels_max = 16, 770 }, 771 .capture = { 772 .channels_min = 1, 773 .channels_max = 16, 774 }, 775 }, 776 #endif 777 }; 778 779 int hda_dsp_dais_suspend(struct snd_sof_dev *sdev) 780 { 781 /* 782 * In the corner case where a SUSPEND happens during a PAUSE, the ALSA core 783 * does not throw the TRIGGER_SUSPEND. This leaves the DAIs in an unbalanced state. 784 * Since the component suspend is called last, we can trap this corner case 785 * and force the DAIs to release their resources. 786 */ 787 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK) 788 int ret; 789 790 ret = hda_dai_suspend(sof_to_bus(sdev)); 791 if (ret < 0) 792 return ret; 793 #endif 794 795 return 0; 796 } 797