1e149ca29SPierre-Louis Bossart // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 2fdd961e3SKeyon Jie // 3fdd961e3SKeyon Jie // This file is provided under a dual BSD/GPLv2 license. When using or 4fdd961e3SKeyon Jie // redistributing this file, you may do so under either license. 5fdd961e3SKeyon Jie // 6fdd961e3SKeyon Jie // Copyright(c) 2018 Intel Corporation. All rights reserved. 7fdd961e3SKeyon Jie // 8fdd961e3SKeyon Jie // Authors: Keyon Jie <yang.jie@linux.intel.com> 9fdd961e3SKeyon Jie // 10fdd961e3SKeyon Jie 11fdd961e3SKeyon Jie #include <sound/pcm_params.h> 12fdd961e3SKeyon Jie #include <sound/hdaudio_ext.h> 13a8338e76SPierre-Louis Bossart #include <sound/hda-mlink.h> 14a8338e76SPierre-Louis Bossart #include <sound/hda_register.h> 151da51943SRanjani Sridharan #include <sound/intel-nhlt.h> 164c30004aSRanjani Sridharan #include <sound/sof/ipc4/header.h> 174c30004aSRanjani Sridharan #include <uapi/sound/sof/header.h> 184c30004aSRanjani Sridharan #include "../ipc4-priv.h" 194c30004aSRanjani Sridharan #include "../ipc4-topology.h" 20fdd961e3SKeyon Jie #include "../sof-priv.h" 21ee1e79b7SRanjani Sridharan #include "../sof-audio.h" 22fdd961e3SKeyon Jie #include "hda.h" 23fdd961e3SKeyon Jie 241da51943SRanjani Sridharan /* 251da51943SRanjani Sridharan * The default method is to fetch NHLT from BIOS. With this parameter set 261da51943SRanjani Sridharan * it is possible to override that with NHLT in the SOF topology manifest. 271da51943SRanjani Sridharan */ 281da51943SRanjani Sridharan static bool hda_use_tplg_nhlt; 291da51943SRanjani Sridharan module_param_named(sof_use_tplg_nhlt, hda_use_tplg_nhlt, bool, 0444); 301da51943SRanjani Sridharan MODULE_PARM_DESC(sof_use_tplg_nhlt, "SOF topology nhlt override"); 311da51943SRanjani Sridharan 32de8e2d5dSPierre-Louis Bossart static struct snd_sof_dev *widget_to_sdev(struct snd_soc_dapm_widget *w) 33de8e2d5dSPierre-Louis Bossart { 34de8e2d5dSPierre-Louis Bossart struct snd_sof_widget *swidget = w->dobj.private; 35de8e2d5dSPierre-Louis Bossart struct snd_soc_component *component = swidget->scomp; 36de8e2d5dSPierre-Louis Bossart 37de8e2d5dSPierre-Louis Bossart return snd_soc_component_get_drvdata(component); 38de8e2d5dSPierre-Louis Bossart } 39de8e2d5dSPierre-Louis Bossart 402b009fa0SRanjani Sridharan int hda_dai_config(struct snd_soc_dapm_widget *w, unsigned int flags, 41e6ffb0d5SRanjani Sridharan struct snd_sof_dai_config_data *data) 42e6ffb0d5SRanjani Sridharan { 43e6ffb0d5SRanjani Sridharan struct snd_sof_widget *swidget = w->dobj.private; 441f7b5d52SPeter Ujfalusi const struct sof_ipc_tplg_ops *tplg_ops; 451f7b5d52SPeter Ujfalusi struct snd_sof_dev *sdev; 46e6ffb0d5SRanjani Sridharan int ret; 47e6ffb0d5SRanjani Sridharan 481f7b5d52SPeter Ujfalusi if (!swidget) 491f7b5d52SPeter Ujfalusi return 0; 501f7b5d52SPeter Ujfalusi 51de8e2d5dSPierre-Louis Bossart sdev = widget_to_sdev(w); 521f7b5d52SPeter Ujfalusi tplg_ops = sof_ipc_get_ops(sdev, tplg); 531f7b5d52SPeter Ujfalusi 54e6ffb0d5SRanjani Sridharan if (tplg_ops && tplg_ops->dai_config) { 55e6ffb0d5SRanjani Sridharan ret = tplg_ops->dai_config(sdev, swidget, flags, data); 56e6ffb0d5SRanjani Sridharan if (ret < 0) { 57e6ffb0d5SRanjani Sridharan dev_err(sdev->dev, "DAI config with flags %x failed for widget %s\n", 58e6ffb0d5SRanjani Sridharan flags, w->name); 59e6ffb0d5SRanjani Sridharan return ret; 60e6ffb0d5SRanjani Sridharan } 61e6ffb0d5SRanjani Sridharan } 62e6ffb0d5SRanjani Sridharan 63e6ffb0d5SRanjani Sridharan return 0; 64e6ffb0d5SRanjani Sridharan } 65e6ffb0d5SRanjani Sridharan 66746a78c2SPierre-Louis Bossart #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK) 672b009fa0SRanjani Sridharan 68de8e2d5dSPierre-Louis Bossart static struct snd_sof_dev *dai_to_sdev(struct snd_pcm_substream *substream, 69de8e2d5dSPierre-Louis Bossart struct snd_soc_dai *cpu_dai) 70de8e2d5dSPierre-Louis Bossart { 71de8e2d5dSPierre-Louis Bossart struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); 72de8e2d5dSPierre-Louis Bossart 73de8e2d5dSPierre-Louis Bossart return widget_to_sdev(w); 74de8e2d5dSPierre-Louis Bossart } 75de8e2d5dSPierre-Louis Bossart 7680afde34SRanjani Sridharan static const struct hda_dai_widget_dma_ops * 7780afde34SRanjani Sridharan hda_dai_get_ops(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) 78fdd961e3SKeyon Jie { 7980afde34SRanjani Sridharan struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); 8080afde34SRanjani Sridharan struct snd_sof_widget *swidget = w->dobj.private; 81de8e2d5dSPierre-Louis Bossart struct snd_sof_dev *sdev; 821f7b5d52SPeter Ujfalusi struct snd_sof_dai *sdai; 831f7b5d52SPeter Ujfalusi 84de8e2d5dSPierre-Louis Bossart sdev = widget_to_sdev(w); 85de8e2d5dSPierre-Louis Bossart 861f7b5d52SPeter Ujfalusi /* 871f7b5d52SPeter Ujfalusi * The swidget parameter of hda_select_dai_widget_ops() is ignored in 881f7b5d52SPeter Ujfalusi * case of DSPless mode 891f7b5d52SPeter Ujfalusi */ 901f7b5d52SPeter Ujfalusi if (sdev->dspless_mode_selected) 911f7b5d52SPeter Ujfalusi return hda_select_dai_widget_ops(sdev, NULL); 921f7b5d52SPeter Ujfalusi 931f7b5d52SPeter Ujfalusi sdai = swidget->private; 94fdd961e3SKeyon Jie 9580afde34SRanjani Sridharan /* select and set the DAI widget ops if not set already */ 9680afde34SRanjani Sridharan if (!sdai->platform_private) { 9780afde34SRanjani Sridharan const struct hda_dai_widget_dma_ops *ops = 9880afde34SRanjani Sridharan hda_select_dai_widget_ops(sdev, swidget); 9980afde34SRanjani Sridharan if (!ops) 100bdf4ad3fSRanjani Sridharan return NULL; 10180afde34SRanjani Sridharan 10280afde34SRanjani Sridharan /* check if mandatory ops are set */ 10380afde34SRanjani Sridharan if (!ops || !ops->get_hext_stream) 10480afde34SRanjani Sridharan return NULL; 10580afde34SRanjani Sridharan 10680afde34SRanjani Sridharan sdai->platform_private = ops; 107fdd961e3SKeyon Jie } 108fdd961e3SKeyon Jie 10980afde34SRanjani Sridharan return sdai->platform_private; 110fdd961e3SKeyon Jie } 111fdd961e3SKeyon Jie 112880924caSPierre-Louis Bossart static int hda_link_dma_cleanup(struct snd_pcm_substream *substream, 1130351a9b8SPierre-Louis Bossart struct hdac_ext_stream *hext_stream, 114d1bf5847SPierre-Louis Bossart struct snd_soc_dai *cpu_dai) 115880924caSPierre-Louis Bossart { 11680afde34SRanjani Sridharan const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai); 117880924caSPierre-Louis Bossart struct sof_intel_hda_stream *hda_stream; 1187f1e16aeSPierre-Louis Bossart struct hdac_ext_link *hlink; 119de8e2d5dSPierre-Louis Bossart struct snd_sof_dev *sdev; 120880924caSPierre-Louis Bossart int stream_tag; 121880924caSPierre-Louis Bossart 122c4be6024SPierre-Louis Bossart if (!ops) { 123c4be6024SPierre-Louis Bossart dev_err(cpu_dai->dev, "DAI widget ops not set\n"); 124c4be6024SPierre-Louis Bossart return -EINVAL; 125c4be6024SPierre-Louis Bossart } 126c4be6024SPierre-Louis Bossart 127de8e2d5dSPierre-Louis Bossart sdev = dai_to_sdev(substream, cpu_dai); 128de8e2d5dSPierre-Louis Bossart 129d1bf5847SPierre-Louis Bossart hlink = ops->get_hlink(sdev, substream); 1307f1e16aeSPierre-Louis Bossart if (!hlink) 131880924caSPierre-Louis Bossart return -EINVAL; 132880924caSPierre-Louis Bossart 133880924caSPierre-Louis Bossart if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 134880924caSPierre-Louis Bossart stream_tag = hdac_stream(hext_stream)->stream_tag; 1357fa403f2SPierre-Louis Bossart snd_hdac_ext_bus_link_clear_stream_id(hlink, stream_tag); 136880924caSPierre-Louis Bossart } 13780afde34SRanjani Sridharan 13880afde34SRanjani Sridharan if (ops->release_hext_stream) 13980afde34SRanjani Sridharan ops->release_hext_stream(sdev, cpu_dai, substream); 14080afde34SRanjani Sridharan 141880924caSPierre-Louis Bossart hext_stream->link_prepared = 0; 142880924caSPierre-Louis Bossart 143880924caSPierre-Louis Bossart /* free the host DMA channel reserved by hostless streams */ 144880924caSPierre-Louis Bossart hda_stream = hstream_to_sof_hda_stream(hext_stream); 145880924caSPierre-Louis Bossart hda_stream->host_reserved = 0; 146880924caSPierre-Louis Bossart 147880924caSPierre-Louis Bossart return 0; 148880924caSPierre-Louis Bossart } 149880924caSPierre-Louis Bossart 150f321ffc8SPierre-Louis Bossart static int hda_link_dma_hw_params(struct snd_pcm_substream *substream, 151b436ed8dSRanjani Sridharan struct snd_pcm_hw_params *params, struct snd_soc_dai *cpu_dai) 152fdd961e3SKeyon Jie { 15380afde34SRanjani Sridharan const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai); 1544842f79fSPierre-Louis Bossart struct hdac_ext_stream *hext_stream; 155a8310c00SRanjani Sridharan struct hdac_stream *hstream; 1567f1e16aeSPierre-Louis Bossart struct hdac_ext_link *hlink; 1574842f79fSPierre-Louis Bossart struct snd_sof_dev *sdev; 15880afde34SRanjani Sridharan int stream_tag; 1594842f79fSPierre-Louis Bossart 160c4be6024SPierre-Louis Bossart if (!ops) { 161c4be6024SPierre-Louis Bossart dev_err(cpu_dai->dev, "DAI widget ops not set\n"); 162c4be6024SPierre-Louis Bossart return -EINVAL; 163c4be6024SPierre-Louis Bossart } 164c4be6024SPierre-Louis Bossart 165de8e2d5dSPierre-Louis Bossart sdev = dai_to_sdev(substream, cpu_dai); 166fdd961e3SKeyon Jie 167d1bf5847SPierre-Louis Bossart hlink = ops->get_hlink(sdev, substream); 1681f810d2bSPierre-Louis Bossart if (!hlink) 1691f810d2bSPierre-Louis Bossart return -EINVAL; 1701f810d2bSPierre-Louis Bossart 17180afde34SRanjani Sridharan hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream); 17280afde34SRanjani Sridharan 1737d88b960SPierre-Louis Bossart if (!hext_stream) { 17480afde34SRanjani Sridharan if (ops->assign_hext_stream) 17580afde34SRanjani Sridharan hext_stream = ops->assign_hext_stream(sdev, cpu_dai, substream); 17680afde34SRanjani Sridharan } 17780afde34SRanjani Sridharan 1787d88b960SPierre-Louis Bossart if (!hext_stream) 179bdf4ad3fSRanjani Sridharan return -EBUSY; 180921162c8SPierre-Louis Bossart 181a8310c00SRanjani Sridharan hstream = &hext_stream->hstream; 182a8310c00SRanjani Sridharan stream_tag = hstream->stream_tag; 183a8310c00SRanjani Sridharan 1842a6afac2SRanjani Sridharan if (hext_stream->hstream.direction == SNDRV_PCM_STREAM_PLAYBACK) 1852a6afac2SRanjani Sridharan snd_hdac_ext_bus_link_set_stream_id(hlink, stream_tag); 1862a6afac2SRanjani Sridharan 18763611041SPierre-Louis Bossart /* set the hdac_stream in the codec dai */ 1882205c63dSPierre-Louis Bossart if (ops->codec_dai_set_stream) 1892205c63dSPierre-Louis Bossart ops->codec_dai_set_stream(sdev, substream, hstream); 190fdd961e3SKeyon Jie 191e2d6569aSRanjani Sridharan if (ops->reset_hext_stream) 192e2d6569aSRanjani Sridharan ops->reset_hext_stream(sdev, hext_stream); 193a8310c00SRanjani Sridharan 194767cda3fSPierre-Louis Bossart if (ops->calc_stream_format && ops->setup_hext_stream) { 195767cda3fSPierre-Louis Bossart unsigned int format_val = ops->calc_stream_format(sdev, substream, params); 196a8310c00SRanjani Sridharan 197e2d6569aSRanjani Sridharan ops->setup_hext_stream(sdev, hext_stream, format_val); 198767cda3fSPierre-Louis Bossart } 199a8310c00SRanjani Sridharan 200a8310c00SRanjani Sridharan hext_stream->link_prepared = 1; 201a8310c00SRanjani Sridharan 202a8310c00SRanjani Sridharan return 0; 203fdd961e3SKeyon Jie } 204fdd961e3SKeyon Jie 205b7b71b8cSPierre-Louis Bossart static int __maybe_unused hda_dai_hw_free(struct snd_pcm_substream *substream, 206b7b71b8cSPierre-Louis Bossart struct snd_soc_dai *cpu_dai) 2079272d6c2SPierre-Louis Bossart { 20880afde34SRanjani Sridharan const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai); 2099272d6c2SPierre-Louis Bossart struct hdac_ext_stream *hext_stream; 210de8e2d5dSPierre-Louis Bossart struct snd_sof_dev *sdev = dai_to_sdev(substream, cpu_dai); 2119272d6c2SPierre-Louis Bossart 21280afde34SRanjani Sridharan if (!ops) { 213c4be6024SPierre-Louis Bossart dev_err(cpu_dai->dev, "DAI widget ops not set\n"); 21480afde34SRanjani Sridharan return -EINVAL; 21580afde34SRanjani Sridharan } 21680afde34SRanjani Sridharan 21780afde34SRanjani Sridharan hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream); 218880924caSPierre-Louis Bossart if (!hext_stream) 2199272d6c2SPierre-Louis Bossart return 0; 220880924caSPierre-Louis Bossart 221d1bf5847SPierre-Louis Bossart return hda_link_dma_cleanup(substream, hext_stream, cpu_dai); 2229272d6c2SPierre-Louis Bossart } 2239272d6c2SPierre-Louis Bossart 224b7b71b8cSPierre-Louis Bossart static int __maybe_unused hda_dai_hw_params(struct snd_pcm_substream *substream, 2259272d6c2SPierre-Louis Bossart struct snd_pcm_hw_params *params, 2269272d6c2SPierre-Louis Bossart struct snd_soc_dai *dai) 2279272d6c2SPierre-Louis Bossart { 228e6ffb0d5SRanjani Sridharan struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, substream->stream); 22980afde34SRanjani Sridharan const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai); 23080afde34SRanjani Sridharan struct hdac_ext_stream *hext_stream; 231e6ffb0d5SRanjani Sridharan struct snd_sof_dai_config_data data = { 0 }; 232e6ffb0d5SRanjani Sridharan unsigned int flags = SOF_DAI_CONFIG_FLAGS_HW_PARAMS; 233de8e2d5dSPierre-Louis Bossart struct snd_sof_dev *sdev = widget_to_sdev(w); 2349272d6c2SPierre-Louis Bossart int ret; 2359272d6c2SPierre-Louis Bossart 23680afde34SRanjani Sridharan if (!ops) { 23780afde34SRanjani Sridharan dev_err(sdev->dev, "DAI widget ops not set\n"); 23880afde34SRanjani Sridharan return -EINVAL; 23980afde34SRanjani Sridharan } 24080afde34SRanjani Sridharan 24180afde34SRanjani Sridharan hext_stream = ops->get_hext_stream(sdev, dai, substream); 242c4eb48f7SPierre-Louis Bossart if (hext_stream && hext_stream->link_prepared) 243c4eb48f7SPierre-Louis Bossart return 0; 244c4eb48f7SPierre-Louis Bossart 245b436ed8dSRanjani Sridharan ret = hda_link_dma_hw_params(substream, params, dai); 2469272d6c2SPierre-Louis Bossart if (ret < 0) 2479272d6c2SPierre-Louis Bossart return ret; 2489272d6c2SPierre-Louis Bossart 249e6ffb0d5SRanjani Sridharan hext_stream = ops->get_hext_stream(sdev, dai, substream); 2509272d6c2SPierre-Louis Bossart 251e6ffb0d5SRanjani Sridharan flags |= SOF_DAI_CONFIG_FLAGS_2_STEP_STOP << SOF_DAI_CONFIG_FLAGS_QUIRK_SHIFT; 252e6ffb0d5SRanjani Sridharan data.dai_data = hdac_stream(hext_stream)->stream_tag - 1; 2539272d6c2SPierre-Louis Bossart 254e6ffb0d5SRanjani Sridharan return hda_dai_config(w, flags, &data); 2559272d6c2SPierre-Louis Bossart } 2569272d6c2SPierre-Louis Bossart 2574c30004aSRanjani Sridharan /* 2584c30004aSRanjani Sridharan * In contrast to IPC3, the dai trigger in IPC4 mixes pipeline state changes 2594c30004aSRanjani Sridharan * (over IPC channel) and DMA state change (direct host register changes). 2604c30004aSRanjani Sridharan */ 261b7b71b8cSPierre-Louis Bossart static int __maybe_unused hda_dai_trigger(struct snd_pcm_substream *substream, int cmd, 262b7b71b8cSPierre-Louis Bossart struct snd_soc_dai *dai) 2634c30004aSRanjani Sridharan { 26480afde34SRanjani Sridharan const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai); 26580afde34SRanjani Sridharan struct hdac_ext_stream *hext_stream; 266de8e2d5dSPierre-Louis Bossart struct snd_sof_dev *sdev; 2674c30004aSRanjani Sridharan int ret; 2684c30004aSRanjani Sridharan 269c4be6024SPierre-Louis Bossart if (!ops) { 270c4be6024SPierre-Louis Bossart dev_err(dai->dev, "DAI widget ops not set\n"); 271c4be6024SPierre-Louis Bossart return -EINVAL; 272c4be6024SPierre-Louis Bossart } 273c4be6024SPierre-Louis Bossart 27418701bb1SPierre-Louis Bossart dev_dbg(dai->dev, "cmd=%d dai %s direction %d\n", cmd, 2754c30004aSRanjani Sridharan dai->name, substream->stream); 2764c30004aSRanjani Sridharan 277de8e2d5dSPierre-Louis Bossart sdev = dai_to_sdev(substream, dai); 278de8e2d5dSPierre-Louis Bossart 27980afde34SRanjani Sridharan hext_stream = ops->get_hext_stream(sdev, dai, substream); 28080afde34SRanjani Sridharan if (!hext_stream) 28180afde34SRanjani Sridharan return -EINVAL; 28280afde34SRanjani Sridharan 2834b2ee4cdSRanjani Sridharan if (ops->pre_trigger) { 2844b2ee4cdSRanjani Sridharan ret = ops->pre_trigger(sdev, dai, substream, cmd); 28537a26eecSRanjani Sridharan if (ret < 0) 28637a26eecSRanjani Sridharan return ret; 28737a26eecSRanjani Sridharan } 28837a26eecSRanjani Sridharan 2894b2ee4cdSRanjani Sridharan if (ops->trigger) { 2904b2ee4cdSRanjani Sridharan ret = ops->trigger(sdev, dai, substream, cmd); 29137a26eecSRanjani Sridharan if (ret < 0) 29237a26eecSRanjani Sridharan return ret; 2934b2ee4cdSRanjani Sridharan } 2944b2ee4cdSRanjani Sridharan 2954b2ee4cdSRanjani Sridharan if (ops->post_trigger) { 2964b2ee4cdSRanjani Sridharan ret = ops->post_trigger(sdev, dai, substream, cmd); 2974b2ee4cdSRanjani Sridharan if (ret < 0) 2984b2ee4cdSRanjani Sridharan return ret; 2994b2ee4cdSRanjani Sridharan } 3004b2ee4cdSRanjani Sridharan 3014b2ee4cdSRanjani Sridharan switch (cmd) { 3024c30004aSRanjani Sridharan case SNDRV_PCM_TRIGGER_SUSPEND: 303d1bf5847SPierre-Louis Bossart ret = hda_link_dma_cleanup(substream, hext_stream, dai); 3044c30004aSRanjani Sridharan if (ret < 0) { 3054c30004aSRanjani Sridharan dev_err(sdev->dev, "%s: failed to clean up link DMA\n", __func__); 3064c30004aSRanjani Sridharan return ret; 3074c30004aSRanjani Sridharan } 3084c30004aSRanjani Sridharan break; 3094c30004aSRanjani Sridharan default: 3104b2ee4cdSRanjani Sridharan break; 3114c30004aSRanjani Sridharan } 3124c30004aSRanjani Sridharan 3134c30004aSRanjani Sridharan return 0; 3144c30004aSRanjani Sridharan } 3154c30004aSRanjani Sridharan 316746a78c2SPierre-Louis Bossart #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) 317746a78c2SPierre-Louis Bossart 318caf7ad84SPierre-Louis Bossart static int hda_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 319caf7ad84SPierre-Louis Bossart { 320caf7ad84SPierre-Louis Bossart struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 321caf7ad84SPierre-Louis Bossart int stream = substream->stream; 322caf7ad84SPierre-Louis Bossart 323caf7ad84SPierre-Louis Bossart return hda_dai_hw_params(substream, &rtd->dpcm[stream].hw_params, dai); 324caf7ad84SPierre-Louis Bossart } 325caf7ad84SPierre-Louis Bossart 3262b009fa0SRanjani Sridharan static const struct snd_soc_dai_ops hda_dai_ops = { 327309e6e55SPierre-Louis Bossart .hw_params = hda_dai_hw_params, 328309e6e55SPierre-Louis Bossart .hw_free = hda_dai_hw_free, 3292b009fa0SRanjani Sridharan .trigger = hda_dai_trigger, 3304c30004aSRanjani Sridharan .prepare = hda_dai_prepare, 331fdd961e3SKeyon Jie }; 33270368106SCezary Rojewski 333746a78c2SPierre-Louis Bossart #endif 334746a78c2SPierre-Louis Bossart 335a8338e76SPierre-Louis Bossart static struct sof_ipc4_copier *widget_to_copier(struct snd_soc_dapm_widget *w) 336a8338e76SPierre-Louis Bossart { 337a8338e76SPierre-Louis Bossart struct snd_sof_widget *swidget = w->dobj.private; 338a8338e76SPierre-Louis Bossart struct snd_sof_dai *sdai = swidget->private; 339a8338e76SPierre-Louis Bossart struct sof_ipc4_copier *ipc4_copier = (struct sof_ipc4_copier *)sdai->private; 340a8338e76SPierre-Louis Bossart 341a8338e76SPierre-Louis Bossart return ipc4_copier; 342a8338e76SPierre-Louis Bossart } 343a8338e76SPierre-Louis Bossart 344a8338e76SPierre-Louis Bossart static int non_hda_dai_hw_params(struct snd_pcm_substream *substream, 345a8338e76SPierre-Louis Bossart struct snd_pcm_hw_params *params, 346a8338e76SPierre-Louis Bossart struct snd_soc_dai *cpu_dai) 347a8338e76SPierre-Louis Bossart { 348a8338e76SPierre-Louis Bossart struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); 349a8338e76SPierre-Louis Bossart struct sof_ipc4_dma_config_tlv *dma_config_tlv; 350a8338e76SPierre-Louis Bossart const struct hda_dai_widget_dma_ops *ops; 351a8338e76SPierre-Louis Bossart struct sof_ipc4_dma_config *dma_config; 352a8338e76SPierre-Louis Bossart struct sof_ipc4_copier *ipc4_copier; 353a8338e76SPierre-Louis Bossart struct hdac_ext_stream *hext_stream; 354a8338e76SPierre-Louis Bossart struct hdac_stream *hstream; 355a8338e76SPierre-Louis Bossart struct snd_sof_dev *sdev; 356a8338e76SPierre-Louis Bossart int stream_id; 357a8338e76SPierre-Louis Bossart int ret; 358a8338e76SPierre-Louis Bossart 359a8338e76SPierre-Louis Bossart ops = hda_dai_get_ops(substream, cpu_dai); 360a8338e76SPierre-Louis Bossart if (!ops) { 361a8338e76SPierre-Louis Bossart dev_err(cpu_dai->dev, "DAI widget ops not set\n"); 362a8338e76SPierre-Louis Bossart return -EINVAL; 363a8338e76SPierre-Louis Bossart } 364a8338e76SPierre-Louis Bossart 365a8338e76SPierre-Louis Bossart /* use HDaudio stream handling */ 366a8338e76SPierre-Louis Bossart ret = hda_dai_hw_params(substream, params, cpu_dai); 367a8338e76SPierre-Louis Bossart if (ret < 0) { 368a8338e76SPierre-Louis Bossart dev_err(cpu_dai->dev, "%s: hda_dai_hw_params failed: %d\n", __func__, ret); 369a8338e76SPierre-Louis Bossart return ret; 370a8338e76SPierre-Louis Bossart } 371a8338e76SPierre-Louis Bossart 372a8338e76SPierre-Louis Bossart /* get stream_id */ 373a8338e76SPierre-Louis Bossart sdev = widget_to_sdev(w); 374a8338e76SPierre-Louis Bossart hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream); 375a8338e76SPierre-Louis Bossart 376a8338e76SPierre-Louis Bossart if (!hext_stream) { 377a8338e76SPierre-Louis Bossart dev_err(cpu_dai->dev, "%s: no hext_stream found\n", __func__); 378a8338e76SPierre-Louis Bossart return -ENODEV; 379a8338e76SPierre-Louis Bossart } 380a8338e76SPierre-Louis Bossart 381a8338e76SPierre-Louis Bossart hstream = &hext_stream->hstream; 382a8338e76SPierre-Louis Bossart stream_id = hstream->stream_tag; 383a8338e76SPierre-Louis Bossart 384a8338e76SPierre-Louis Bossart if (!stream_id) { 385a8338e76SPierre-Louis Bossart dev_err(cpu_dai->dev, "%s: no stream_id allocated\n", __func__); 386a8338e76SPierre-Louis Bossart return -ENODEV; 387a8338e76SPierre-Louis Bossart } 388a8338e76SPierre-Louis Bossart 389a8338e76SPierre-Louis Bossart /* configure TLV */ 390a8338e76SPierre-Louis Bossart ipc4_copier = widget_to_copier(w); 391a8338e76SPierre-Louis Bossart 392a8338e76SPierre-Louis Bossart dma_config_tlv = &ipc4_copier->dma_config_tlv; 393a8338e76SPierre-Louis Bossart dma_config_tlv->type = SOF_IPC4_GTW_DMA_CONFIG_ID; 394a8338e76SPierre-Louis Bossart /* dma_config_priv_size is zero */ 395a8338e76SPierre-Louis Bossart dma_config_tlv->length = sizeof(dma_config_tlv->dma_config); 396a8338e76SPierre-Louis Bossart 397a8338e76SPierre-Louis Bossart dma_config = &dma_config_tlv->dma_config; 398a8338e76SPierre-Louis Bossart 399a8338e76SPierre-Louis Bossart dma_config->dma_method = SOF_IPC4_DMA_METHOD_HDA; 400a8338e76SPierre-Louis Bossart dma_config->pre_allocated_by_host = 1; 401a8338e76SPierre-Louis Bossart dma_config->dma_channel_id = stream_id - 1; 402a8338e76SPierre-Louis Bossart dma_config->stream_id = stream_id; 403a8338e76SPierre-Louis Bossart dma_config->dma_stream_channel_map.device_count = 0; /* mapping not used */ 404a8338e76SPierre-Louis Bossart dma_config->dma_priv_config_size = 0; 405a8338e76SPierre-Louis Bossart 406a8338e76SPierre-Louis Bossart return 0; 407a8338e76SPierre-Louis Bossart } 408a8338e76SPierre-Louis Bossart 409a8338e76SPierre-Louis Bossart static int non_hda_dai_prepare(struct snd_pcm_substream *substream, 410a8338e76SPierre-Louis Bossart struct snd_soc_dai *cpu_dai) 411a8338e76SPierre-Louis Bossart { 412a8338e76SPierre-Louis Bossart struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 413a8338e76SPierre-Louis Bossart int stream = substream->stream; 414a8338e76SPierre-Louis Bossart 415a8338e76SPierre-Louis Bossart return non_hda_dai_hw_params(substream, &rtd->dpcm[stream].hw_params, cpu_dai); 416a8338e76SPierre-Louis Bossart } 417a8338e76SPierre-Louis Bossart 418a8338e76SPierre-Louis Bossart static const struct snd_soc_dai_ops ssp_dai_ops = { 419a8338e76SPierre-Louis Bossart .hw_params = non_hda_dai_hw_params, 420a8338e76SPierre-Louis Bossart .hw_free = hda_dai_hw_free, 421a8338e76SPierre-Louis Bossart .trigger = hda_dai_trigger, 422a8338e76SPierre-Louis Bossart .prepare = non_hda_dai_prepare, 423a8338e76SPierre-Louis Bossart }; 424a8338e76SPierre-Louis Bossart 425b6c508b4SPierre-Louis Bossart static const struct snd_soc_dai_ops dmic_dai_ops = { 426b6c508b4SPierre-Louis Bossart .hw_params = non_hda_dai_hw_params, 427b6c508b4SPierre-Louis Bossart .hw_free = hda_dai_hw_free, 428b6c508b4SPierre-Louis Bossart .trigger = hda_dai_trigger, 429b6c508b4SPierre-Louis Bossart .prepare = non_hda_dai_prepare, 430b6c508b4SPierre-Louis Bossart }; 431b6c508b4SPierre-Louis Bossart 432*2960ee5cSPierre-Louis Bossart int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream, 433*2960ee5cSPierre-Louis Bossart struct snd_pcm_hw_params *params, 434*2960ee5cSPierre-Louis Bossart struct snd_soc_dai *cpu_dai, 435*2960ee5cSPierre-Louis Bossart int link_id) 436*2960ee5cSPierre-Louis Bossart { 437*2960ee5cSPierre-Louis Bossart struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); 438*2960ee5cSPierre-Louis Bossart const struct hda_dai_widget_dma_ops *ops; 439*2960ee5cSPierre-Louis Bossart struct hdac_ext_stream *hext_stream; 440*2960ee5cSPierre-Louis Bossart struct snd_sof_dev *sdev; 441*2960ee5cSPierre-Louis Bossart int ret; 442*2960ee5cSPierre-Louis Bossart 443*2960ee5cSPierre-Louis Bossart ret = non_hda_dai_hw_params(substream, params, cpu_dai); 444*2960ee5cSPierre-Louis Bossart if (ret < 0) { 445*2960ee5cSPierre-Louis Bossart dev_err(cpu_dai->dev, "%s: non_hda_dai_hw_params failed %d\n", __func__, ret); 446*2960ee5cSPierre-Louis Bossart return ret; 447*2960ee5cSPierre-Louis Bossart } 448*2960ee5cSPierre-Louis Bossart 449*2960ee5cSPierre-Louis Bossart ops = hda_dai_get_ops(substream, cpu_dai); 450*2960ee5cSPierre-Louis Bossart sdev = widget_to_sdev(w); 451*2960ee5cSPierre-Louis Bossart hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream); 452*2960ee5cSPierre-Louis Bossart 453*2960ee5cSPierre-Louis Bossart if (!hext_stream) 454*2960ee5cSPierre-Louis Bossart return -ENODEV; 455*2960ee5cSPierre-Louis Bossart 456*2960ee5cSPierre-Louis Bossart /* in the case of SoundWire we need to program the PCMSyCM registers */ 457*2960ee5cSPierre-Louis Bossart ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id, cpu_dai->id, 458*2960ee5cSPierre-Louis Bossart GENMASK(params_channels(params) - 1, 0), 459*2960ee5cSPierre-Louis Bossart hdac_stream(hext_stream)->stream_tag, 460*2960ee5cSPierre-Louis Bossart substream->stream); 461*2960ee5cSPierre-Louis Bossart if (ret < 0) { 462*2960ee5cSPierre-Louis Bossart dev_err(cpu_dai->dev, "%s: hdac_bus_eml_sdw_map_stream_ch failed %d\n", 463*2960ee5cSPierre-Louis Bossart __func__, ret); 464*2960ee5cSPierre-Louis Bossart return ret; 465*2960ee5cSPierre-Louis Bossart } 466*2960ee5cSPierre-Louis Bossart 467*2960ee5cSPierre-Louis Bossart return 0; 468*2960ee5cSPierre-Louis Bossart } 469*2960ee5cSPierre-Louis Bossart 470*2960ee5cSPierre-Louis Bossart int sdw_hda_dai_hw_free(struct snd_pcm_substream *substream, 471*2960ee5cSPierre-Louis Bossart struct snd_soc_dai *cpu_dai, 472*2960ee5cSPierre-Louis Bossart int link_id) 473*2960ee5cSPierre-Louis Bossart { 474*2960ee5cSPierre-Louis Bossart struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); 475*2960ee5cSPierre-Louis Bossart struct snd_sof_dev *sdev; 476*2960ee5cSPierre-Louis Bossart int ret; 477*2960ee5cSPierre-Louis Bossart 478*2960ee5cSPierre-Louis Bossart ret = hda_dai_hw_free(substream, cpu_dai); 479*2960ee5cSPierre-Louis Bossart if (ret < 0) { 480*2960ee5cSPierre-Louis Bossart dev_err(cpu_dai->dev, "%s: non_hda_dai_hw_free failed %d\n", __func__, ret); 481*2960ee5cSPierre-Louis Bossart return ret; 482*2960ee5cSPierre-Louis Bossart } 483*2960ee5cSPierre-Louis Bossart 484*2960ee5cSPierre-Louis Bossart sdev = widget_to_sdev(w); 485*2960ee5cSPierre-Louis Bossart 486*2960ee5cSPierre-Louis Bossart /* in the case of SoundWire we need to reset the PCMSyCM registers */ 487*2960ee5cSPierre-Louis Bossart ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id, cpu_dai->id, 488*2960ee5cSPierre-Louis Bossart 0, 0, substream->stream); 489*2960ee5cSPierre-Louis Bossart if (ret < 0) { 490*2960ee5cSPierre-Louis Bossart dev_err(cpu_dai->dev, "%s: hdac_bus_eml_sdw_map_stream_ch failed %d\n", 491*2960ee5cSPierre-Louis Bossart __func__, ret); 492*2960ee5cSPierre-Louis Bossart return ret; 493*2960ee5cSPierre-Louis Bossart } 494*2960ee5cSPierre-Louis Bossart 495*2960ee5cSPierre-Louis Bossart return 0; 496*2960ee5cSPierre-Louis Bossart } 497*2960ee5cSPierre-Louis Bossart 498*2960ee5cSPierre-Louis Bossart int sdw_hda_dai_trigger(struct snd_pcm_substream *substream, int cmd, 499*2960ee5cSPierre-Louis Bossart struct snd_soc_dai *cpu_dai) 500*2960ee5cSPierre-Louis Bossart { 501*2960ee5cSPierre-Louis Bossart return hda_dai_trigger(substream, cmd, cpu_dai); 502*2960ee5cSPierre-Louis Bossart } 503*2960ee5cSPierre-Louis Bossart 504f09e9284SPierre-Louis Bossart static int hda_dai_suspend(struct hdac_bus *bus) 505f09e9284SPierre-Louis Bossart { 506f09e9284SPierre-Louis Bossart struct snd_soc_pcm_runtime *rtd; 507f09e9284SPierre-Louis Bossart struct hdac_ext_stream *hext_stream; 508f09e9284SPierre-Louis Bossart struct hdac_stream *s; 50923b1944eSPierre-Louis Bossart int ret; 510f09e9284SPierre-Louis Bossart 511f09e9284SPierre-Louis Bossart /* set internal flag for BE */ 512f09e9284SPierre-Louis Bossart list_for_each_entry(s, &bus->stream_list, list) { 513722cbbfaSPierre-Louis Bossart 514f09e9284SPierre-Louis Bossart hext_stream = stream_to_hdac_ext_stream(s); 515f09e9284SPierre-Louis Bossart 516f09e9284SPierre-Louis Bossart /* 517f09e9284SPierre-Louis Bossart * clear stream. This should already be taken care for running 518f09e9284SPierre-Louis Bossart * streams when the SUSPEND trigger is called. But paused 519f09e9284SPierre-Louis Bossart * streams do not get suspended, so this needs to be done 520f09e9284SPierre-Louis Bossart * explicitly during suspend. 521f09e9284SPierre-Louis Bossart */ 522f09e9284SPierre-Louis Bossart if (hext_stream->link_substream) { 5232b009fa0SRanjani Sridharan const struct hda_dai_widget_dma_ops *ops; 5242b009fa0SRanjani Sridharan struct snd_sof_widget *swidget; 5252b009fa0SRanjani Sridharan struct snd_soc_dapm_widget *w; 5262b009fa0SRanjani Sridharan struct snd_soc_dai *cpu_dai; 5272b009fa0SRanjani Sridharan struct snd_sof_dev *sdev; 5282b009fa0SRanjani Sridharan struct snd_sof_dai *sdai; 52923b1944eSPierre-Louis Bossart 530f09e9284SPierre-Louis Bossart rtd = asoc_substream_to_rtd(hext_stream->link_substream); 53123b1944eSPierre-Louis Bossart cpu_dai = asoc_rtd_to_cpu(rtd, 0); 5322b009fa0SRanjani Sridharan w = snd_soc_dai_get_widget(cpu_dai, hdac_stream(hext_stream)->direction); 5332b009fa0SRanjani Sridharan swidget = w->dobj.private; 534de8e2d5dSPierre-Louis Bossart sdev = widget_to_sdev(w); 5352b009fa0SRanjani Sridharan sdai = swidget->private; 5362b009fa0SRanjani Sridharan ops = sdai->platform_private; 537f09e9284SPierre-Louis Bossart 5380351a9b8SPierre-Louis Bossart ret = hda_link_dma_cleanup(hext_stream->link_substream, 5390351a9b8SPierre-Louis Bossart hext_stream, 540d1bf5847SPierre-Louis Bossart cpu_dai); 541880924caSPierre-Louis Bossart if (ret < 0) 542880924caSPierre-Louis Bossart return ret; 543722cbbfaSPierre-Louis Bossart 5442b009fa0SRanjani Sridharan /* for consistency with TRIGGER_SUSPEND */ 5452b009fa0SRanjani Sridharan if (ops->post_trigger) { 5462b009fa0SRanjani Sridharan ret = ops->post_trigger(sdev, cpu_dai, 5472b009fa0SRanjani Sridharan hext_stream->link_substream, 5482b009fa0SRanjani Sridharan SNDRV_PCM_TRIGGER_SUSPEND); 54923b1944eSPierre-Louis Bossart if (ret < 0) 55023b1944eSPierre-Louis Bossart return ret; 55123b1944eSPierre-Louis Bossart } 552f09e9284SPierre-Louis Bossart } 5532b009fa0SRanjani Sridharan } 554f09e9284SPierre-Louis Bossart 555f09e9284SPierre-Louis Bossart return 0; 556f09e9284SPierre-Louis Bossart } 5574c30004aSRanjani Sridharan 558a8338e76SPierre-Louis Bossart static void ssp_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) 559a8338e76SPierre-Louis Bossart { 560a8338e76SPierre-Louis Bossart const struct sof_intel_dsp_desc *chip; 561a8338e76SPierre-Louis Bossart int i; 562a8338e76SPierre-Louis Bossart 563a8338e76SPierre-Louis Bossart chip = get_chip_info(sdev->pdata); 564a8338e76SPierre-Louis Bossart 565a8338e76SPierre-Louis Bossart if (chip->hw_ip_version >= SOF_INTEL_ACE_2_0) { 566a8338e76SPierre-Louis Bossart for (i = 0; i < ops->num_drv; i++) { 567a8338e76SPierre-Louis Bossart if (strstr(ops->drv[i].name, "SSP")) 568a8338e76SPierre-Louis Bossart ops->drv[i].ops = &ssp_dai_ops; 569a8338e76SPierre-Louis Bossart } 570a8338e76SPierre-Louis Bossart } 571a8338e76SPierre-Louis Bossart } 572a8338e76SPierre-Louis Bossart 573b6c508b4SPierre-Louis Bossart static void dmic_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) 574b6c508b4SPierre-Louis Bossart { 575b6c508b4SPierre-Louis Bossart const struct sof_intel_dsp_desc *chip; 576b6c508b4SPierre-Louis Bossart int i; 577b6c508b4SPierre-Louis Bossart 578b6c508b4SPierre-Louis Bossart chip = get_chip_info(sdev->pdata); 579b6c508b4SPierre-Louis Bossart 580b6c508b4SPierre-Louis Bossart if (chip->hw_ip_version >= SOF_INTEL_ACE_2_0) { 581b6c508b4SPierre-Louis Bossart for (i = 0; i < ops->num_drv; i++) { 582b6c508b4SPierre-Louis Bossart if (strstr(ops->drv[i].name, "DMIC")) 583b6c508b4SPierre-Louis Bossart ops->drv[i].ops = &dmic_dai_ops; 584b6c508b4SPierre-Louis Bossart } 585b6c508b4SPierre-Louis Bossart } 586b6c508b4SPierre-Louis Bossart } 587b6c508b4SPierre-Louis Bossart 588a8338e76SPierre-Louis Bossart #else 589a8338e76SPierre-Louis Bossart 590a8338e76SPierre-Louis Bossart static inline void ssp_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) {} 591b6c508b4SPierre-Louis Bossart static inline void dmic_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) {} 592a8338e76SPierre-Louis Bossart 593a8338e76SPierre-Louis Bossart #endif /* CONFIG_SND_SOC_SOF_HDA_LINK */ 59470368106SCezary Rojewski 59551ec71dcSRanjani Sridharan void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) 59651ec71dcSRanjani Sridharan { 59751ec71dcSRanjani Sridharan int i; 59851ec71dcSRanjani Sridharan 59951ec71dcSRanjani Sridharan for (i = 0; i < ops->num_drv; i++) { 600a4203256SPierre-Louis Bossart #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) 60151ec71dcSRanjani Sridharan if (strstr(ops->drv[i].name, "iDisp") || 60251ec71dcSRanjani Sridharan strstr(ops->drv[i].name, "Analog") || 60351ec71dcSRanjani Sridharan strstr(ops->drv[i].name, "Digital")) 6042b009fa0SRanjani Sridharan ops->drv[i].ops = &hda_dai_ops; 60551ec71dcSRanjani Sridharan #endif 60651ec71dcSRanjani Sridharan } 6072b009fa0SRanjani Sridharan 608a8338e76SPierre-Louis Bossart ssp_set_dai_drv_ops(sdev, ops); 609b6c508b4SPierre-Louis Bossart dmic_set_dai_drv_ops(sdev, ops); 610a8338e76SPierre-Louis Bossart 6112b009fa0SRanjani Sridharan if (sdev->pdata->ipc_type == SOF_INTEL_IPC4 && !hda_use_tplg_nhlt) { 6121da51943SRanjani Sridharan struct sof_ipc4_fw_data *ipc4_data = sdev->private; 6131da51943SRanjani Sridharan 6141da51943SRanjani Sridharan ipc4_data->nhlt = intel_nhlt_init(sdev->dev); 61551ec71dcSRanjani Sridharan } 61651ec71dcSRanjani Sridharan } 61751ec71dcSRanjani Sridharan 6181da51943SRanjani Sridharan void hda_ops_free(struct snd_sof_dev *sdev) 6191da51943SRanjani Sridharan { 6201da51943SRanjani Sridharan if (sdev->pdata->ipc_type == SOF_INTEL_IPC4) { 6211da51943SRanjani Sridharan struct sof_ipc4_fw_data *ipc4_data = sdev->private; 6221da51943SRanjani Sridharan 6231da51943SRanjani Sridharan if (!hda_use_tplg_nhlt) 6241da51943SRanjani Sridharan intel_nhlt_free(ipc4_data->nhlt); 6251da51943SRanjani Sridharan } 6261da51943SRanjani Sridharan } 6271da51943SRanjani Sridharan EXPORT_SYMBOL_NS(hda_ops_free, SND_SOC_SOF_INTEL_HDA_COMMON); 6281da51943SRanjani Sridharan 629fdd961e3SKeyon Jie /* 630fdd961e3SKeyon Jie * common dai driver for skl+ platforms. 631fdd961e3SKeyon Jie * some products who use this DAI array only physically have a subset of 632fdd961e3SKeyon Jie * the DAIs, but no harm is done here by adding the whole set. 633fdd961e3SKeyon Jie */ 634fdd961e3SKeyon Jie struct snd_soc_dai_driver skl_dai[] = { 635fdd961e3SKeyon Jie { 636fdd961e3SKeyon Jie .name = "SSP0 Pin", 637e81d47e9SBard Liao .playback = { 638e81d47e9SBard Liao .channels_min = 1, 639e81d47e9SBard Liao .channels_max = 8, 640e81d47e9SBard Liao }, 641e81d47e9SBard Liao .capture = { 642e81d47e9SBard Liao .channels_min = 1, 643e81d47e9SBard Liao .channels_max = 8, 644e81d47e9SBard Liao }, 645fdd961e3SKeyon Jie }, 646fdd961e3SKeyon Jie { 647fdd961e3SKeyon Jie .name = "SSP1 Pin", 648e81d47e9SBard Liao .playback = { 649e81d47e9SBard Liao .channels_min = 1, 650e81d47e9SBard Liao .channels_max = 8, 651e81d47e9SBard Liao }, 652e81d47e9SBard Liao .capture = { 653e81d47e9SBard Liao .channels_min = 1, 654e81d47e9SBard Liao .channels_max = 8, 655e81d47e9SBard Liao }, 656fdd961e3SKeyon Jie }, 657fdd961e3SKeyon Jie { 658fdd961e3SKeyon Jie .name = "SSP2 Pin", 659e81d47e9SBard Liao .playback = { 660e81d47e9SBard Liao .channels_min = 1, 661e81d47e9SBard Liao .channels_max = 8, 662e81d47e9SBard Liao }, 663e81d47e9SBard Liao .capture = { 664e81d47e9SBard Liao .channels_min = 1, 665e81d47e9SBard Liao .channels_max = 8, 666e81d47e9SBard Liao }, 667fdd961e3SKeyon Jie }, 668fdd961e3SKeyon Jie { 669fdd961e3SKeyon Jie .name = "SSP3 Pin", 670e81d47e9SBard Liao .playback = { 671e81d47e9SBard Liao .channels_min = 1, 672e81d47e9SBard Liao .channels_max = 8, 673e81d47e9SBard Liao }, 674e81d47e9SBard Liao .capture = { 675e81d47e9SBard Liao .channels_min = 1, 676e81d47e9SBard Liao .channels_max = 8, 677e81d47e9SBard Liao }, 678fdd961e3SKeyon Jie }, 679fdd961e3SKeyon Jie { 680fdd961e3SKeyon Jie .name = "SSP4 Pin", 681e81d47e9SBard Liao .playback = { 682e81d47e9SBard Liao .channels_min = 1, 683e81d47e9SBard Liao .channels_max = 8, 684e81d47e9SBard Liao }, 685e81d47e9SBard Liao .capture = { 686e81d47e9SBard Liao .channels_min = 1, 687e81d47e9SBard Liao .channels_max = 8, 688e81d47e9SBard Liao }, 689fdd961e3SKeyon Jie }, 690fdd961e3SKeyon Jie { 691fdd961e3SKeyon Jie .name = "SSP5 Pin", 692e81d47e9SBard Liao .playback = { 693e81d47e9SBard Liao .channels_min = 1, 694e81d47e9SBard Liao .channels_max = 8, 695e81d47e9SBard Liao }, 696e81d47e9SBard Liao .capture = { 697e81d47e9SBard Liao .channels_min = 1, 698e81d47e9SBard Liao .channels_max = 8, 699e81d47e9SBard Liao }, 700fdd961e3SKeyon Jie }, 701fdd961e3SKeyon Jie { 702fdd961e3SKeyon Jie .name = "DMIC01 Pin", 703e81d47e9SBard Liao .capture = { 704e81d47e9SBard Liao .channels_min = 1, 705e81d47e9SBard Liao .channels_max = 4, 706e81d47e9SBard Liao }, 707fdd961e3SKeyon Jie }, 708fdd961e3SKeyon Jie { 709fdd961e3SKeyon Jie .name = "DMIC16k Pin", 710e81d47e9SBard Liao .capture = { 711e81d47e9SBard Liao .channels_min = 1, 712e81d47e9SBard Liao .channels_max = 4, 713e81d47e9SBard Liao }, 714fdd961e3SKeyon Jie }, 715a4203256SPierre-Louis Bossart #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) 716fdd961e3SKeyon Jie { 717fdd961e3SKeyon Jie .name = "iDisp1 Pin", 718e81d47e9SBard Liao .playback = { 719e81d47e9SBard Liao .channels_min = 1, 720e81d47e9SBard Liao .channels_max = 8, 721e81d47e9SBard Liao }, 722fdd961e3SKeyon Jie }, 723fdd961e3SKeyon Jie { 724fdd961e3SKeyon Jie .name = "iDisp2 Pin", 725e81d47e9SBard Liao .playback = { 726e81d47e9SBard Liao .channels_min = 1, 727e81d47e9SBard Liao .channels_max = 8, 728e81d47e9SBard Liao }, 729fdd961e3SKeyon Jie }, 730fdd961e3SKeyon Jie { 731fdd961e3SKeyon Jie .name = "iDisp3 Pin", 732e81d47e9SBard Liao .playback = { 733e81d47e9SBard Liao .channels_min = 1, 734e81d47e9SBard Liao .channels_max = 8, 735e81d47e9SBard Liao }, 736fdd961e3SKeyon Jie }, 737fdd961e3SKeyon Jie { 738e68d6696SSathyanarayana Nujella .name = "iDisp4 Pin", 739e81d47e9SBard Liao .playback = { 740e81d47e9SBard Liao .channels_min = 1, 741e81d47e9SBard Liao .channels_max = 8, 742e81d47e9SBard Liao }, 743e68d6696SSathyanarayana Nujella }, 744e68d6696SSathyanarayana Nujella { 745fdd961e3SKeyon Jie .name = "Analog CPU DAI", 746e81d47e9SBard Liao .playback = { 747e81d47e9SBard Liao .channels_min = 1, 748e81d47e9SBard Liao .channels_max = 16, 749e81d47e9SBard Liao }, 750e81d47e9SBard Liao .capture = { 751e81d47e9SBard Liao .channels_min = 1, 752e81d47e9SBard Liao .channels_max = 16, 753e81d47e9SBard Liao }, 754fdd961e3SKeyon Jie }, 755fdd961e3SKeyon Jie { 756fdd961e3SKeyon Jie .name = "Digital CPU DAI", 757e81d47e9SBard Liao .playback = { 758e81d47e9SBard Liao .channels_min = 1, 759e81d47e9SBard Liao .channels_max = 16, 760e81d47e9SBard Liao }, 761e81d47e9SBard Liao .capture = { 762e81d47e9SBard Liao .channels_min = 1, 763e81d47e9SBard Liao .channels_max = 16, 764e81d47e9SBard Liao }, 765fdd961e3SKeyon Jie }, 766fdd961e3SKeyon Jie { 767fdd961e3SKeyon Jie .name = "Alt Analog CPU DAI", 768e81d47e9SBard Liao .playback = { 769e81d47e9SBard Liao .channels_min = 1, 770e81d47e9SBard Liao .channels_max = 16, 771e81d47e9SBard Liao }, 772e81d47e9SBard Liao .capture = { 773e81d47e9SBard Liao .channels_min = 1, 774e81d47e9SBard Liao .channels_max = 16, 775e81d47e9SBard Liao }, 776fdd961e3SKeyon Jie }, 777fdd961e3SKeyon Jie #endif 778fdd961e3SKeyon Jie }; 779f09e9284SPierre-Louis Bossart 780f09e9284SPierre-Louis Bossart int hda_dsp_dais_suspend(struct snd_sof_dev *sdev) 781f09e9284SPierre-Louis Bossart { 782f09e9284SPierre-Louis Bossart /* 783f09e9284SPierre-Louis Bossart * In the corner case where a SUSPEND happens during a PAUSE, the ALSA core 784f09e9284SPierre-Louis Bossart * does not throw the TRIGGER_SUSPEND. This leaves the DAIs in an unbalanced state. 785f09e9284SPierre-Louis Bossart * Since the component suspend is called last, we can trap this corner case 786f09e9284SPierre-Louis Bossart * and force the DAIs to release their resources. 787f09e9284SPierre-Louis Bossart */ 788746a78c2SPierre-Louis Bossart #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK) 789f09e9284SPierre-Louis Bossart int ret; 790f09e9284SPierre-Louis Bossart 791f09e9284SPierre-Louis Bossart ret = hda_dai_suspend(sof_to_bus(sdev)); 792f09e9284SPierre-Louis Bossart if (ret < 0) 793f09e9284SPierre-Louis Bossart return ret; 794f09e9284SPierre-Louis Bossart #endif 795f09e9284SPierre-Louis Bossart 796f09e9284SPierre-Louis Bossart return 0; 797f09e9284SPierre-Louis Bossart } 798