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> 131da51943SRanjani Sridharan #include <sound/intel-nhlt.h> 144c30004aSRanjani Sridharan #include <sound/sof/ipc4/header.h> 154c30004aSRanjani Sridharan #include <uapi/sound/sof/header.h> 164c30004aSRanjani Sridharan #include "../ipc4-priv.h" 174c30004aSRanjani Sridharan #include "../ipc4-topology.h" 18fdd961e3SKeyon Jie #include "../sof-priv.h" 19ee1e79b7SRanjani Sridharan #include "../sof-audio.h" 20fdd961e3SKeyon Jie #include "hda.h" 21fdd961e3SKeyon Jie 221da51943SRanjani Sridharan /* 231da51943SRanjani Sridharan * The default method is to fetch NHLT from BIOS. With this parameter set 241da51943SRanjani Sridharan * it is possible to override that with NHLT in the SOF topology manifest. 251da51943SRanjani Sridharan */ 261da51943SRanjani Sridharan static bool hda_use_tplg_nhlt; 271da51943SRanjani Sridharan module_param_named(sof_use_tplg_nhlt, hda_use_tplg_nhlt, bool, 0444); 281da51943SRanjani Sridharan MODULE_PARM_DESC(sof_use_tplg_nhlt, "SOF topology nhlt override"); 291da51943SRanjani Sridharan 30a4203256SPierre-Louis Bossart #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) 31fdd961e3SKeyon Jie 32*80afde34SRanjani Sridharan static const struct hda_dai_widget_dma_ops * 33*80afde34SRanjani Sridharan hda_dai_get_ops(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) 34fdd961e3SKeyon Jie { 35*80afde34SRanjani Sridharan struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream); 36*80afde34SRanjani Sridharan struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(cpu_dai->component); 37*80afde34SRanjani Sridharan struct snd_sof_widget *swidget = w->dobj.private; 38*80afde34SRanjani Sridharan struct snd_sof_dai *sdai = swidget->private; 39fdd961e3SKeyon Jie 40*80afde34SRanjani Sridharan /* select and set the DAI widget ops if not set already */ 41*80afde34SRanjani Sridharan if (!sdai->platform_private) { 42*80afde34SRanjani Sridharan const struct hda_dai_widget_dma_ops *ops = 43*80afde34SRanjani Sridharan hda_select_dai_widget_ops(sdev, swidget); 44fdd961e3SKeyon Jie 45*80afde34SRanjani Sridharan if (!ops) 46bdf4ad3fSRanjani Sridharan return NULL; 47*80afde34SRanjani Sridharan 48*80afde34SRanjani Sridharan /* check if mandatory ops are set */ 49*80afde34SRanjani Sridharan if (!ops || !ops->get_hext_stream) 50*80afde34SRanjani Sridharan return NULL; 51*80afde34SRanjani Sridharan 52*80afde34SRanjani Sridharan sdai->platform_private = ops; 53fdd961e3SKeyon Jie } 54fdd961e3SKeyon Jie 55*80afde34SRanjani Sridharan return sdai->platform_private; 56fdd961e3SKeyon Jie } 57fdd961e3SKeyon Jie 58880924caSPierre-Louis Bossart static int hda_link_dma_cleanup(struct snd_pcm_substream *substream, 590351a9b8SPierre-Louis Bossart struct hdac_ext_stream *hext_stream, 60880924caSPierre-Louis Bossart struct snd_soc_dai *cpu_dai, 612be2caf4SRanjani Sridharan struct snd_soc_dai *codec_dai) 62880924caSPierre-Louis Bossart { 63*80afde34SRanjani Sridharan struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(cpu_dai->component); 64*80afde34SRanjani Sridharan const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai); 650351a9b8SPierre-Louis Bossart struct hdac_stream *hstream = &hext_stream->hstream; 66880924caSPierre-Louis Bossart struct hdac_bus *bus = hstream->bus; 67880924caSPierre-Louis Bossart struct sof_intel_hda_stream *hda_stream; 687f1e16aeSPierre-Louis Bossart struct hdac_ext_link *hlink; 69880924caSPierre-Louis Bossart int stream_tag; 70880924caSPierre-Louis Bossart 71b0cd60f3SPierre-Louis Bossart hlink = snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name); 727f1e16aeSPierre-Louis Bossart if (!hlink) 73880924caSPierre-Louis Bossart return -EINVAL; 74880924caSPierre-Louis Bossart 75880924caSPierre-Louis Bossart if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 76880924caSPierre-Louis Bossart stream_tag = hdac_stream(hext_stream)->stream_tag; 777fa403f2SPierre-Louis Bossart snd_hdac_ext_bus_link_clear_stream_id(hlink, stream_tag); 78880924caSPierre-Louis Bossart } 79*80afde34SRanjani Sridharan 80*80afde34SRanjani Sridharan if (ops->release_hext_stream) 81*80afde34SRanjani Sridharan ops->release_hext_stream(sdev, cpu_dai, substream); 82*80afde34SRanjani Sridharan 83880924caSPierre-Louis Bossart hext_stream->link_prepared = 0; 84880924caSPierre-Louis Bossart 85880924caSPierre-Louis Bossart /* free the host DMA channel reserved by hostless streams */ 86880924caSPierre-Louis Bossart hda_stream = hstream_to_sof_hda_stream(hext_stream); 87880924caSPierre-Louis Bossart hda_stream->host_reserved = 0; 88880924caSPierre-Louis Bossart 89880924caSPierre-Louis Bossart return 0; 90880924caSPierre-Louis Bossart } 91880924caSPierre-Louis Bossart 92f321ffc8SPierre-Louis Bossart static int hda_link_dma_hw_params(struct snd_pcm_substream *substream, 93b436ed8dSRanjani Sridharan struct snd_pcm_hw_params *params, struct snd_soc_dai *cpu_dai) 94fdd961e3SKeyon Jie { 95*80afde34SRanjani Sridharan const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai); 961205300aSKuninori Morimoto struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 97be3e8de7SKuninori Morimoto struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 984842f79fSPierre-Louis Bossart struct hdac_ext_stream *hext_stream; 99a8310c00SRanjani Sridharan struct hdac_stream *hstream; 1007f1e16aeSPierre-Louis Bossart struct hdac_ext_link *hlink; 1014842f79fSPierre-Louis Bossart struct snd_sof_dev *sdev; 1024842f79fSPierre-Louis Bossart struct hdac_bus *bus; 103a8310c00SRanjani Sridharan unsigned int format_val; 1042a6afac2SRanjani Sridharan unsigned int link_bps; 105*80afde34SRanjani Sridharan int stream_tag; 1064842f79fSPierre-Louis Bossart 1074842f79fSPierre-Louis Bossart sdev = snd_soc_component_get_drvdata(cpu_dai->component); 1084842f79fSPierre-Louis Bossart bus = sof_to_bus(sdev); 109fdd961e3SKeyon Jie 1101f810d2bSPierre-Louis Bossart hlink = snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name); 1111f810d2bSPierre-Louis Bossart if (!hlink) 1121f810d2bSPierre-Louis Bossart return -EINVAL; 1131f810d2bSPierre-Louis Bossart 114*80afde34SRanjani Sridharan hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream); 115*80afde34SRanjani Sridharan 1167d88b960SPierre-Louis Bossart if (!hext_stream) { 117*80afde34SRanjani Sridharan if (ops->assign_hext_stream) 118*80afde34SRanjani Sridharan hext_stream = ops->assign_hext_stream(sdev, cpu_dai, substream); 119*80afde34SRanjani Sridharan } 120*80afde34SRanjani Sridharan 1217d88b960SPierre-Louis Bossart if (!hext_stream) 122bdf4ad3fSRanjani Sridharan return -EBUSY; 123921162c8SPierre-Louis Bossart 124a8310c00SRanjani Sridharan hstream = &hext_stream->hstream; 125a8310c00SRanjani Sridharan stream_tag = hstream->stream_tag; 126a8310c00SRanjani Sridharan 1272a6afac2SRanjani Sridharan if (hext_stream->hstream.direction == SNDRV_PCM_STREAM_PLAYBACK) 1282a6afac2SRanjani Sridharan snd_hdac_ext_bus_link_set_stream_id(hlink, stream_tag); 1292a6afac2SRanjani Sridharan 13063611041SPierre-Louis Bossart /* set the hdac_stream in the codec dai */ 1317d88b960SPierre-Louis Bossart snd_soc_dai_set_stream(codec_dai, hdac_stream(hext_stream), substream->stream); 132fdd961e3SKeyon Jie 133fdd961e3SKeyon Jie if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 1342a6afac2SRanjani Sridharan link_bps = codec_dai->driver->playback.sig_bits; 135fdd961e3SKeyon Jie else 1362a6afac2SRanjani Sridharan link_bps = codec_dai->driver->capture.sig_bits; 137fdd961e3SKeyon Jie 138a8310c00SRanjani Sridharan snd_hdac_ext_stream_reset(hext_stream); 139a8310c00SRanjani Sridharan 1402a6afac2SRanjani Sridharan format_val = snd_hdac_calc_stream_format(params_rate(params), params_channels(params), 1412a6afac2SRanjani Sridharan params_format(params), link_bps, 0); 142a8310c00SRanjani Sridharan 143a8310c00SRanjani Sridharan dev_dbg(bus->dev, "format_val=%d, rate=%d, ch=%d, format=%d\n", 1442a6afac2SRanjani Sridharan format_val, params_rate(params), params_channels(params), params_format(params)); 145a8310c00SRanjani Sridharan 146a8310c00SRanjani Sridharan snd_hdac_ext_stream_setup(hext_stream, format_val); 147a8310c00SRanjani Sridharan 148a8310c00SRanjani Sridharan hext_stream->link_prepared = 1; 149a8310c00SRanjani Sridharan 150a8310c00SRanjani Sridharan return 0; 151fdd961e3SKeyon Jie } 152fdd961e3SKeyon Jie 153b436ed8dSRanjani Sridharan static int hda_link_dma_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) 154f321ffc8SPierre-Louis Bossart { 1551205300aSKuninori Morimoto struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 156fdd961e3SKeyon Jie int stream = substream->stream; 157fdd961e3SKeyon Jie 158b436ed8dSRanjani Sridharan return hda_link_dma_hw_params(substream, &rtd->dpcm[stream].hw_params, cpu_dai); 159fdd961e3SKeyon Jie } 160fdd961e3SKeyon Jie 161b436ed8dSRanjani Sridharan static int hda_link_dma_trigger(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai, 162b436ed8dSRanjani Sridharan int cmd) 163f321ffc8SPierre-Louis Bossart { 164*80afde34SRanjani Sridharan const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai); 165f321ffc8SPierre-Louis Bossart struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 166*80afde34SRanjani Sridharan struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(cpu_dai->component); 167f321ffc8SPierre-Louis Bossart struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 168*80afde34SRanjani Sridharan struct hdac_ext_stream *hext_stream; 169880924caSPierre-Louis Bossart int ret; 170bdf4ad3fSRanjani Sridharan 171*80afde34SRanjani Sridharan hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream); 172*80afde34SRanjani Sridharan 173722cbbfaSPierre-Louis Bossart if (!hext_stream) 174722cbbfaSPierre-Louis Bossart return 0; 175722cbbfaSPierre-Louis Bossart 176fdd961e3SKeyon Jie switch (cmd) { 177fdd961e3SKeyon Jie case SNDRV_PCM_TRIGGER_START: 178fdd961e3SKeyon Jie case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 17900b6cd95SPierre-Louis Bossart snd_hdac_ext_stream_start(hext_stream); 180fdd961e3SKeyon Jie break; 181fdd961e3SKeyon Jie case SNDRV_PCM_TRIGGER_SUSPEND: 182a3ebccb5SKai Vehmanen case SNDRV_PCM_TRIGGER_STOP: 1832be2caf4SRanjani Sridharan snd_hdac_ext_stream_clear(hext_stream); 1842be2caf4SRanjani Sridharan ret = hda_link_dma_cleanup(substream, hext_stream, cpu_dai, codec_dai); 185880924caSPierre-Louis Bossart if (ret < 0) 186880924caSPierre-Louis Bossart return ret; 187722cbbfaSPierre-Louis Bossart 188e14cddc5SRanjani Sridharan break; 189bdf4ad3fSRanjani Sridharan case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 19000b6cd95SPierre-Louis Bossart snd_hdac_ext_stream_clear(hext_stream); 19169acac56SRanjani Sridharan 192fdd961e3SKeyon Jie break; 193fdd961e3SKeyon Jie default: 194fdd961e3SKeyon Jie return -EINVAL; 195fdd961e3SKeyon Jie } 196fdd961e3SKeyon Jie return 0; 197fdd961e3SKeyon Jie } 198fdd961e3SKeyon Jie 199b436ed8dSRanjani Sridharan static int hda_link_dma_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) 2009272d6c2SPierre-Louis Bossart { 201*80afde34SRanjani Sridharan struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(cpu_dai->component); 202*80afde34SRanjani Sridharan const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai); 2039272d6c2SPierre-Louis Bossart struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 2049272d6c2SPierre-Louis Bossart struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 2059272d6c2SPierre-Louis Bossart struct hdac_ext_stream *hext_stream; 2069272d6c2SPierre-Louis Bossart 207*80afde34SRanjani Sridharan if (!ops) { 208*80afde34SRanjani Sridharan dev_err(sdev->dev, "DAI widget ops not set\n"); 209*80afde34SRanjani Sridharan return -EINVAL; 210*80afde34SRanjani Sridharan } 211*80afde34SRanjani Sridharan 212*80afde34SRanjani Sridharan hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream); 213880924caSPierre-Louis Bossart if (!hext_stream) 2149272d6c2SPierre-Louis Bossart return 0; 215880924caSPierre-Louis Bossart 2162be2caf4SRanjani Sridharan return hda_link_dma_cleanup(substream, hext_stream, cpu_dai, codec_dai); 2179272d6c2SPierre-Louis Bossart } 2189272d6c2SPierre-Louis Bossart 2199272d6c2SPierre-Louis Bossart static int hda_dai_widget_update(struct snd_soc_dapm_widget *w, 2209272d6c2SPierre-Louis Bossart int channel, bool widget_setup) 2219272d6c2SPierre-Louis Bossart { 2229272d6c2SPierre-Louis Bossart struct snd_sof_dai_config_data data; 2239272d6c2SPierre-Louis Bossart 2249272d6c2SPierre-Louis Bossart data.dai_data = channel; 2259272d6c2SPierre-Louis Bossart 2269272d6c2SPierre-Louis Bossart /* set up/free DAI widget and send DAI_CONFIG IPC */ 2279272d6c2SPierre-Louis Bossart if (widget_setup) 2289272d6c2SPierre-Louis Bossart return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_2_STEP_STOP, &data); 2299272d6c2SPierre-Louis Bossart 2309272d6c2SPierre-Louis Bossart return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE, &data); 2319272d6c2SPierre-Louis Bossart } 2329272d6c2SPierre-Louis Bossart 2339272d6c2SPierre-Louis Bossart static int hda_dai_hw_params_update(struct snd_pcm_substream *substream, 2349272d6c2SPierre-Louis Bossart struct snd_pcm_hw_params *params, 2359272d6c2SPierre-Louis Bossart struct snd_soc_dai *dai) 2369272d6c2SPierre-Louis Bossart { 237*80afde34SRanjani Sridharan struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, substream->stream); 238*80afde34SRanjani Sridharan const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai); 239*80afde34SRanjani Sridharan struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component); 2409272d6c2SPierre-Louis Bossart struct hdac_ext_stream *hext_stream; 2419272d6c2SPierre-Louis Bossart int stream_tag; 2429272d6c2SPierre-Louis Bossart 243*80afde34SRanjani Sridharan hext_stream = ops->get_hext_stream(sdev, dai, substream); 2449272d6c2SPierre-Louis Bossart if (!hext_stream) 2459272d6c2SPierre-Louis Bossart return -EINVAL; 2469272d6c2SPierre-Louis Bossart 2479272d6c2SPierre-Louis Bossart stream_tag = hdac_stream(hext_stream)->stream_tag; 2489272d6c2SPierre-Louis Bossart 2499272d6c2SPierre-Louis Bossart /* set up the DAI widget and send the DAI_CONFIG with the new tag */ 2509272d6c2SPierre-Louis Bossart return hda_dai_widget_update(w, stream_tag - 1, true); 2519272d6c2SPierre-Louis Bossart } 2529272d6c2SPierre-Louis Bossart 2539272d6c2SPierre-Louis Bossart static int hda_dai_hw_params(struct snd_pcm_substream *substream, 2549272d6c2SPierre-Louis Bossart struct snd_pcm_hw_params *params, 2559272d6c2SPierre-Louis Bossart struct snd_soc_dai *dai) 2569272d6c2SPierre-Louis Bossart { 257*80afde34SRanjani Sridharan struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component); 258*80afde34SRanjani Sridharan const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai); 259*80afde34SRanjani Sridharan struct hdac_ext_stream *hext_stream; 2609272d6c2SPierre-Louis Bossart int ret; 2619272d6c2SPierre-Louis Bossart 262*80afde34SRanjani Sridharan if (!ops) { 263*80afde34SRanjani Sridharan dev_err(sdev->dev, "DAI widget ops not set\n"); 264*80afde34SRanjani Sridharan return -EINVAL; 265*80afde34SRanjani Sridharan } 266*80afde34SRanjani Sridharan 267*80afde34SRanjani Sridharan hext_stream = ops->get_hext_stream(sdev, dai, substream); 268c4eb48f7SPierre-Louis Bossart if (hext_stream && hext_stream->link_prepared) 269c4eb48f7SPierre-Louis Bossart return 0; 270c4eb48f7SPierre-Louis Bossart 271b436ed8dSRanjani Sridharan ret = hda_link_dma_hw_params(substream, params, dai); 2729272d6c2SPierre-Louis Bossart if (ret < 0) 2739272d6c2SPierre-Louis Bossart return ret; 2749272d6c2SPierre-Louis Bossart 2759272d6c2SPierre-Louis Bossart return hda_dai_hw_params_update(substream, params, dai); 2769272d6c2SPierre-Louis Bossart } 2779272d6c2SPierre-Louis Bossart 2789272d6c2SPierre-Louis Bossart 2799272d6c2SPierre-Louis Bossart static int hda_dai_config_pause_push_ipc(struct snd_soc_dapm_widget *w) 2809272d6c2SPierre-Louis Bossart { 2819272d6c2SPierre-Louis Bossart struct snd_sof_widget *swidget = w->dobj.private; 2829272d6c2SPierre-Louis Bossart struct snd_soc_component *component = swidget->scomp; 2839272d6c2SPierre-Louis Bossart struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); 2849272d6c2SPierre-Louis Bossart const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; 2859272d6c2SPierre-Louis Bossart int ret = 0; 2869272d6c2SPierre-Louis Bossart 2879272d6c2SPierre-Louis Bossart if (tplg_ops->dai_config) { 2889272d6c2SPierre-Louis Bossart ret = tplg_ops->dai_config(sdev, swidget, SOF_DAI_CONFIG_FLAGS_PAUSE, NULL); 2899272d6c2SPierre-Louis Bossart if (ret < 0) 2909272d6c2SPierre-Louis Bossart dev_err(sdev->dev, "%s: DAI config failed for widget %s\n", __func__, 2919272d6c2SPierre-Louis Bossart w->name); 2929272d6c2SPierre-Louis Bossart } 2939272d6c2SPierre-Louis Bossart 2949272d6c2SPierre-Louis Bossart return ret; 2959272d6c2SPierre-Louis Bossart } 2969272d6c2SPierre-Louis Bossart 2974c30004aSRanjani Sridharan static int hda_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 2989272d6c2SPierre-Louis Bossart { 2999272d6c2SPierre-Louis Bossart struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component); 300*80afde34SRanjani Sridharan const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai); 3019272d6c2SPierre-Louis Bossart struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 302*80afde34SRanjani Sridharan struct hdac_ext_stream *hext_stream; 3039272d6c2SPierre-Louis Bossart int stream = substream->stream; 3049272d6c2SPierre-Louis Bossart int ret; 3059272d6c2SPierre-Louis Bossart 306*80afde34SRanjani Sridharan hext_stream = ops->get_hext_stream(sdev, dai, substream); 307722cbbfaSPierre-Louis Bossart if (hext_stream && hext_stream->link_prepared) 3089272d6c2SPierre-Louis Bossart return 0; 3099272d6c2SPierre-Louis Bossart 31018701bb1SPierre-Louis Bossart dev_dbg(sdev->dev, "prepare stream dir %d\n", substream->stream); 3119272d6c2SPierre-Louis Bossart 312b436ed8dSRanjani Sridharan ret = hda_link_dma_prepare(substream, dai); 3139272d6c2SPierre-Louis Bossart if (ret < 0) 3149272d6c2SPierre-Louis Bossart return ret; 3159272d6c2SPierre-Louis Bossart 3169272d6c2SPierre-Louis Bossart return hda_dai_hw_params_update(substream, &rtd->dpcm[stream].hw_params, dai); 3179272d6c2SPierre-Louis Bossart } 3189272d6c2SPierre-Louis Bossart 31981622503SPierre-Louis Bossart static int hda_dai_hw_free_ipc(int stream, /* direction */ 32081622503SPierre-Louis Bossart struct snd_soc_dai *dai) 32181622503SPierre-Louis Bossart { 32281622503SPierre-Louis Bossart struct snd_soc_dapm_widget *w; 32381622503SPierre-Louis Bossart 32481622503SPierre-Louis Bossart w = snd_soc_dai_get_widget(dai, stream); 32581622503SPierre-Louis Bossart 32681622503SPierre-Louis Bossart /* free the link DMA channel in the FW and the DAI widget */ 32781622503SPierre-Louis Bossart return hda_dai_widget_update(w, DMA_CHAN_INVALID, false); 32881622503SPierre-Louis Bossart } 3299272d6c2SPierre-Louis Bossart 330f321ffc8SPierre-Louis Bossart static int ipc3_hda_dai_trigger(struct snd_pcm_substream *substream, 331f321ffc8SPierre-Louis Bossart int cmd, struct snd_soc_dai *dai) 332fdd961e3SKeyon Jie { 3330acb48ddSRanjani Sridharan struct snd_soc_dapm_widget *w; 334bdf4ad3fSRanjani Sridharan int ret; 335fdd961e3SKeyon Jie 33618701bb1SPierre-Louis Bossart dev_dbg(dai->dev, "cmd=%d dai %s direction %d\n", cmd, 337519d1130SPierre-Louis Bossart dai->name, substream->stream); 338519d1130SPierre-Louis Bossart 339b436ed8dSRanjani Sridharan ret = hda_link_dma_trigger(substream, dai, cmd); 340f321ffc8SPierre-Louis Bossart if (ret < 0) 341f321ffc8SPierre-Louis Bossart return ret; 342bdf4ad3fSRanjani Sridharan 3435ef85c9eSPierre-Louis Bossart w = snd_soc_dai_get_widget(dai, substream->stream); 3440acb48ddSRanjani Sridharan 345f321ffc8SPierre-Louis Bossart switch (cmd) { 346f321ffc8SPierre-Louis Bossart case SNDRV_PCM_TRIGGER_SUSPEND: 347f321ffc8SPierre-Louis Bossart case SNDRV_PCM_TRIGGER_STOP: 348f321ffc8SPierre-Louis Bossart /* 349f321ffc8SPierre-Louis Bossart * free DAI widget during stop/suspend to keep widget use_count's balanced. 350f321ffc8SPierre-Louis Bossart */ 35181622503SPierre-Louis Bossart ret = hda_dai_hw_free_ipc(substream->stream, dai); 352bdf4ad3fSRanjani Sridharan if (ret < 0) 353bdf4ad3fSRanjani Sridharan return ret; 354bdf4ad3fSRanjani Sridharan 355f321ffc8SPierre-Louis Bossart break; 356f321ffc8SPierre-Louis Bossart case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 357f321ffc8SPierre-Louis Bossart ret = hda_dai_config_pause_push_ipc(w); 358f321ffc8SPierre-Louis Bossart if (ret < 0) 359f321ffc8SPierre-Louis Bossart return ret; 360f321ffc8SPierre-Louis Bossart break; 361f321ffc8SPierre-Louis Bossart 362f321ffc8SPierre-Louis Bossart default: 363f321ffc8SPierre-Louis Bossart break; 364f321ffc8SPierre-Louis Bossart } 365f321ffc8SPierre-Louis Bossart return 0; 366f321ffc8SPierre-Louis Bossart } 367f321ffc8SPierre-Louis Bossart 3684c30004aSRanjani Sridharan /* 3694c30004aSRanjani Sridharan * In contrast to IPC3, the dai trigger in IPC4 mixes pipeline state changes 3704c30004aSRanjani Sridharan * (over IPC channel) and DMA state change (direct host register changes). 3714c30004aSRanjani Sridharan */ 3724c30004aSRanjani Sridharan static int ipc4_hda_dai_trigger(struct snd_pcm_substream *substream, 3734c30004aSRanjani Sridharan int cmd, struct snd_soc_dai *dai) 3744c30004aSRanjani Sridharan { 375*80afde34SRanjani Sridharan struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, substream->stream); 3764c30004aSRanjani Sridharan struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component); 377*80afde34SRanjani Sridharan const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai); 378*80afde34SRanjani Sridharan struct snd_sof_widget *swidget = w->dobj.private; 379*80afde34SRanjani Sridharan struct hdac_ext_stream *hext_stream; 380*80afde34SRanjani Sridharan struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; 381*80afde34SRanjani Sridharan struct sof_ipc4_pipeline *pipeline = pipe_widget->private; 3824c30004aSRanjani Sridharan struct snd_soc_pcm_runtime *rtd; 3834c30004aSRanjani Sridharan struct snd_soc_dai *codec_dai; 3844c30004aSRanjani Sridharan int ret; 3854c30004aSRanjani Sridharan 38618701bb1SPierre-Louis Bossart dev_dbg(dai->dev, "cmd=%d dai %s direction %d\n", cmd, 3874c30004aSRanjani Sridharan dai->name, substream->stream); 3884c30004aSRanjani Sridharan 389*80afde34SRanjani Sridharan hext_stream = ops->get_hext_stream(sdev, dai, substream); 390*80afde34SRanjani Sridharan if (!hext_stream) 391*80afde34SRanjani Sridharan return -EINVAL; 392*80afde34SRanjani Sridharan 3934c30004aSRanjani Sridharan rtd = asoc_substream_to_rtd(substream); 3944c30004aSRanjani Sridharan codec_dai = asoc_rtd_to_codec(rtd, 0); 3954c30004aSRanjani Sridharan 3964c30004aSRanjani Sridharan switch (cmd) { 3974c30004aSRanjani Sridharan case SNDRV_PCM_TRIGGER_START: 3984c30004aSRanjani Sridharan case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 39900b6cd95SPierre-Louis Bossart snd_hdac_ext_stream_start(hext_stream); 40037a26eecSRanjani Sridharan if (pipeline->state != SOF_IPC4_PIPE_PAUSED) { 40137a26eecSRanjani Sridharan ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, 40237a26eecSRanjani Sridharan SOF_IPC4_PIPE_PAUSED); 40337a26eecSRanjani Sridharan if (ret < 0) 40437a26eecSRanjani Sridharan return ret; 40537a26eecSRanjani Sridharan pipeline->state = SOF_IPC4_PIPE_PAUSED; 40637a26eecSRanjani Sridharan } 40737a26eecSRanjani Sridharan 40837a26eecSRanjani Sridharan ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, 40937a26eecSRanjani Sridharan SOF_IPC4_PIPE_RUNNING); 41037a26eecSRanjani Sridharan if (ret < 0) 41137a26eecSRanjani Sridharan return ret; 41237a26eecSRanjani Sridharan pipeline->state = SOF_IPC4_PIPE_RUNNING; 4134c30004aSRanjani Sridharan break; 4144c30004aSRanjani Sridharan case SNDRV_PCM_TRIGGER_SUSPEND: 4154c30004aSRanjani Sridharan case SNDRV_PCM_TRIGGER_STOP: 4164c30004aSRanjani Sridharan { 417a2ba1f70SBard Liao ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, 4184c30004aSRanjani Sridharan SOF_IPC4_PIPE_PAUSED); 4194c30004aSRanjani Sridharan if (ret < 0) 4204c30004aSRanjani Sridharan return ret; 4214c30004aSRanjani Sridharan 4224c30004aSRanjani Sridharan pipeline->state = SOF_IPC4_PIPE_PAUSED; 4234c30004aSRanjani Sridharan 42400b6cd95SPierre-Louis Bossart snd_hdac_ext_stream_clear(hext_stream); 4254c30004aSRanjani Sridharan 426a2ba1f70SBard Liao ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, 4274c30004aSRanjani Sridharan SOF_IPC4_PIPE_RESET); 4284c30004aSRanjani Sridharan if (ret < 0) 4294c30004aSRanjani Sridharan return ret; 4304c30004aSRanjani Sridharan 4314c30004aSRanjani Sridharan pipeline->state = SOF_IPC4_PIPE_RESET; 4324c30004aSRanjani Sridharan 433be7f4f8dSRanjani Sridharan ret = hda_link_dma_cleanup(substream, hext_stream, dai, codec_dai); 4344c30004aSRanjani Sridharan if (ret < 0) { 4354c30004aSRanjani Sridharan dev_err(sdev->dev, "%s: failed to clean up link DMA\n", __func__); 4364c30004aSRanjani Sridharan return ret; 4374c30004aSRanjani Sridharan } 4384c30004aSRanjani Sridharan break; 4394c30004aSRanjani Sridharan } 4404c30004aSRanjani Sridharan case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 4414c30004aSRanjani Sridharan { 442a2ba1f70SBard Liao ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id, 4434c30004aSRanjani Sridharan SOF_IPC4_PIPE_PAUSED); 4444c30004aSRanjani Sridharan if (ret < 0) 4454c30004aSRanjani Sridharan return ret; 4464c30004aSRanjani Sridharan 4474c30004aSRanjani Sridharan pipeline->state = SOF_IPC4_PIPE_PAUSED; 4484c30004aSRanjani Sridharan 44900b6cd95SPierre-Louis Bossart snd_hdac_ext_stream_clear(hext_stream); 4504c30004aSRanjani Sridharan break; 4514c30004aSRanjani Sridharan } 4524c30004aSRanjani Sridharan default: 4534c30004aSRanjani Sridharan dev_err(sdev->dev, "%s: unknown trigger command %d\n", __func__, cmd); 4544c30004aSRanjani Sridharan return -EINVAL; 4554c30004aSRanjani Sridharan } 4564c30004aSRanjani Sridharan 4574c30004aSRanjani Sridharan return 0; 4584c30004aSRanjani Sridharan } 4594c30004aSRanjani Sridharan 460f321ffc8SPierre-Louis Bossart static int hda_dai_hw_free(struct snd_pcm_substream *substream, 461f321ffc8SPierre-Louis Bossart struct snd_soc_dai *dai) 462f321ffc8SPierre-Louis Bossart { 463f321ffc8SPierre-Louis Bossart int ret; 464f321ffc8SPierre-Louis Bossart 465b436ed8dSRanjani Sridharan ret = hda_link_dma_hw_free(substream, dai); 466f321ffc8SPierre-Louis Bossart if (ret < 0) 467f321ffc8SPierre-Louis Bossart return ret; 468f321ffc8SPierre-Louis Bossart 46981622503SPierre-Louis Bossart return hda_dai_hw_free_ipc(substream->stream, dai); 470f321ffc8SPierre-Louis Bossart } 471f321ffc8SPierre-Louis Bossart 472309e6e55SPierre-Louis Bossart static const struct snd_soc_dai_ops ipc3_hda_dai_ops = { 473309e6e55SPierre-Louis Bossart .hw_params = hda_dai_hw_params, 474309e6e55SPierre-Louis Bossart .hw_free = hda_dai_hw_free, 475309e6e55SPierre-Louis Bossart .trigger = ipc3_hda_dai_trigger, 4764c30004aSRanjani Sridharan .prepare = hda_dai_prepare, 477fdd961e3SKeyon Jie }; 47870368106SCezary Rojewski 479f09e9284SPierre-Louis Bossart static int hda_dai_suspend(struct hdac_bus *bus) 480f09e9284SPierre-Louis Bossart { 481f09e9284SPierre-Louis Bossart struct snd_soc_pcm_runtime *rtd; 482f09e9284SPierre-Louis Bossart struct hdac_ext_stream *hext_stream; 483f09e9284SPierre-Louis Bossart struct hdac_stream *s; 48423b1944eSPierre-Louis Bossart int ret; 485f09e9284SPierre-Louis Bossart 486f09e9284SPierre-Louis Bossart /* set internal flag for BE */ 487f09e9284SPierre-Louis Bossart list_for_each_entry(s, &bus->stream_list, list) { 488722cbbfaSPierre-Louis Bossart 489f09e9284SPierre-Louis Bossart hext_stream = stream_to_hdac_ext_stream(s); 490f09e9284SPierre-Louis Bossart 491f09e9284SPierre-Louis Bossart /* 492f09e9284SPierre-Louis Bossart * clear stream. This should already be taken care for running 493f09e9284SPierre-Louis Bossart * streams when the SUSPEND trigger is called. But paused 494f09e9284SPierre-Louis Bossart * streams do not get suspended, so this needs to be done 495f09e9284SPierre-Louis Bossart * explicitly during suspend. 496f09e9284SPierre-Louis Bossart */ 497f09e9284SPierre-Louis Bossart if (hext_stream->link_substream) { 49823b1944eSPierre-Louis Bossart struct snd_soc_dai *cpu_dai; 49923b1944eSPierre-Louis Bossart struct snd_soc_dai *codec_dai; 50023b1944eSPierre-Louis Bossart 501f09e9284SPierre-Louis Bossart rtd = asoc_substream_to_rtd(hext_stream->link_substream); 50223b1944eSPierre-Louis Bossart cpu_dai = asoc_rtd_to_cpu(rtd, 0); 50323b1944eSPierre-Louis Bossart codec_dai = asoc_rtd_to_codec(rtd, 0); 504f09e9284SPierre-Louis Bossart 5050351a9b8SPierre-Louis Bossart ret = hda_link_dma_cleanup(hext_stream->link_substream, 5060351a9b8SPierre-Louis Bossart hext_stream, 5072be2caf4SRanjani Sridharan cpu_dai, codec_dai); 508880924caSPierre-Louis Bossart if (ret < 0) 509880924caSPierre-Louis Bossart return ret; 510722cbbfaSPierre-Louis Bossart 51123b1944eSPierre-Louis Bossart /* for consistency with TRIGGER_SUSPEND we free DAI resources */ 51223b1944eSPierre-Louis Bossart ret = hda_dai_hw_free_ipc(hdac_stream(hext_stream)->direction, cpu_dai); 51323b1944eSPierre-Louis Bossart if (ret < 0) 51423b1944eSPierre-Louis Bossart return ret; 51523b1944eSPierre-Louis Bossart } 516f09e9284SPierre-Louis Bossart } 517f09e9284SPierre-Louis Bossart 518f09e9284SPierre-Louis Bossart return 0; 519f09e9284SPierre-Louis Bossart } 5204c30004aSRanjani Sridharan 5214c30004aSRanjani Sridharan static const struct snd_soc_dai_ops ipc4_hda_dai_ops = { 5224c30004aSRanjani Sridharan .hw_params = hda_dai_hw_params, 5234c30004aSRanjani Sridharan .hw_free = hda_dai_hw_free, 5244c30004aSRanjani Sridharan .trigger = ipc4_hda_dai_trigger, 5254c30004aSRanjani Sridharan .prepare = hda_dai_prepare, 5264c30004aSRanjani Sridharan }; 5274c30004aSRanjani Sridharan 528fdd961e3SKeyon Jie #endif 529fdd961e3SKeyon Jie 53051ec71dcSRanjani Sridharan void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) 53151ec71dcSRanjani Sridharan { 53251ec71dcSRanjani Sridharan int i; 53351ec71dcSRanjani Sridharan 53451ec71dcSRanjani Sridharan switch (sdev->pdata->ipc_type) { 53551ec71dcSRanjani Sridharan case SOF_IPC: 53651ec71dcSRanjani Sridharan for (i = 0; i < ops->num_drv; i++) { 537a4203256SPierre-Louis Bossart #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) 53851ec71dcSRanjani Sridharan if (strstr(ops->drv[i].name, "iDisp") || 53951ec71dcSRanjani Sridharan strstr(ops->drv[i].name, "Analog") || 54051ec71dcSRanjani Sridharan strstr(ops->drv[i].name, "Digital")) 541309e6e55SPierre-Louis Bossart ops->drv[i].ops = &ipc3_hda_dai_ops; 54251ec71dcSRanjani Sridharan #endif 54351ec71dcSRanjani Sridharan } 54451ec71dcSRanjani Sridharan break; 5454c30004aSRanjani Sridharan case SOF_INTEL_IPC4: 5461da51943SRanjani Sridharan { 5471da51943SRanjani Sridharan struct sof_ipc4_fw_data *ipc4_data = sdev->private; 5481da51943SRanjani Sridharan 5494c30004aSRanjani Sridharan for (i = 0; i < ops->num_drv; i++) { 550a4203256SPierre-Louis Bossart #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) 5514c30004aSRanjani Sridharan if (strstr(ops->drv[i].name, "iDisp") || 5524c30004aSRanjani Sridharan strstr(ops->drv[i].name, "Analog") || 5534c30004aSRanjani Sridharan strstr(ops->drv[i].name, "Digital")) 5544c30004aSRanjani Sridharan ops->drv[i].ops = &ipc4_hda_dai_ops; 5554c30004aSRanjani Sridharan #endif 5564c30004aSRanjani Sridharan } 5571da51943SRanjani Sridharan 5581da51943SRanjani Sridharan if (!hda_use_tplg_nhlt) 5591da51943SRanjani Sridharan ipc4_data->nhlt = intel_nhlt_init(sdev->dev); 5601da51943SRanjani Sridharan 5614c30004aSRanjani Sridharan break; 5621da51943SRanjani Sridharan } 56351ec71dcSRanjani Sridharan default: 56451ec71dcSRanjani Sridharan break; 56551ec71dcSRanjani Sridharan } 56651ec71dcSRanjani Sridharan } 56751ec71dcSRanjani Sridharan 5681da51943SRanjani Sridharan void hda_ops_free(struct snd_sof_dev *sdev) 5691da51943SRanjani Sridharan { 5701da51943SRanjani Sridharan if (sdev->pdata->ipc_type == SOF_INTEL_IPC4) { 5711da51943SRanjani Sridharan struct sof_ipc4_fw_data *ipc4_data = sdev->private; 5721da51943SRanjani Sridharan 5731da51943SRanjani Sridharan if (!hda_use_tplg_nhlt) 5741da51943SRanjani Sridharan intel_nhlt_free(ipc4_data->nhlt); 5751da51943SRanjani Sridharan } 5761da51943SRanjani Sridharan } 5771da51943SRanjani Sridharan EXPORT_SYMBOL_NS(hda_ops_free, SND_SOC_SOF_INTEL_HDA_COMMON); 5781da51943SRanjani Sridharan 579fdd961e3SKeyon Jie /* 580fdd961e3SKeyon Jie * common dai driver for skl+ platforms. 581fdd961e3SKeyon Jie * some products who use this DAI array only physically have a subset of 582fdd961e3SKeyon Jie * the DAIs, but no harm is done here by adding the whole set. 583fdd961e3SKeyon Jie */ 584fdd961e3SKeyon Jie struct snd_soc_dai_driver skl_dai[] = { 585fdd961e3SKeyon Jie { 586fdd961e3SKeyon Jie .name = "SSP0 Pin", 587e81d47e9SBard Liao .playback = { 588e81d47e9SBard Liao .channels_min = 1, 589e81d47e9SBard Liao .channels_max = 8, 590e81d47e9SBard Liao }, 591e81d47e9SBard Liao .capture = { 592e81d47e9SBard Liao .channels_min = 1, 593e81d47e9SBard Liao .channels_max = 8, 594e81d47e9SBard Liao }, 595fdd961e3SKeyon Jie }, 596fdd961e3SKeyon Jie { 597fdd961e3SKeyon Jie .name = "SSP1 Pin", 598e81d47e9SBard Liao .playback = { 599e81d47e9SBard Liao .channels_min = 1, 600e81d47e9SBard Liao .channels_max = 8, 601e81d47e9SBard Liao }, 602e81d47e9SBard Liao .capture = { 603e81d47e9SBard Liao .channels_min = 1, 604e81d47e9SBard Liao .channels_max = 8, 605e81d47e9SBard Liao }, 606fdd961e3SKeyon Jie }, 607fdd961e3SKeyon Jie { 608fdd961e3SKeyon Jie .name = "SSP2 Pin", 609e81d47e9SBard Liao .playback = { 610e81d47e9SBard Liao .channels_min = 1, 611e81d47e9SBard Liao .channels_max = 8, 612e81d47e9SBard Liao }, 613e81d47e9SBard Liao .capture = { 614e81d47e9SBard Liao .channels_min = 1, 615e81d47e9SBard Liao .channels_max = 8, 616e81d47e9SBard Liao }, 617fdd961e3SKeyon Jie }, 618fdd961e3SKeyon Jie { 619fdd961e3SKeyon Jie .name = "SSP3 Pin", 620e81d47e9SBard Liao .playback = { 621e81d47e9SBard Liao .channels_min = 1, 622e81d47e9SBard Liao .channels_max = 8, 623e81d47e9SBard Liao }, 624e81d47e9SBard Liao .capture = { 625e81d47e9SBard Liao .channels_min = 1, 626e81d47e9SBard Liao .channels_max = 8, 627e81d47e9SBard Liao }, 628fdd961e3SKeyon Jie }, 629fdd961e3SKeyon Jie { 630fdd961e3SKeyon Jie .name = "SSP4 Pin", 631e81d47e9SBard Liao .playback = { 632e81d47e9SBard Liao .channels_min = 1, 633e81d47e9SBard Liao .channels_max = 8, 634e81d47e9SBard Liao }, 635e81d47e9SBard Liao .capture = { 636e81d47e9SBard Liao .channels_min = 1, 637e81d47e9SBard Liao .channels_max = 8, 638e81d47e9SBard Liao }, 639fdd961e3SKeyon Jie }, 640fdd961e3SKeyon Jie { 641fdd961e3SKeyon Jie .name = "SSP5 Pin", 642e81d47e9SBard Liao .playback = { 643e81d47e9SBard Liao .channels_min = 1, 644e81d47e9SBard Liao .channels_max = 8, 645e81d47e9SBard Liao }, 646e81d47e9SBard Liao .capture = { 647e81d47e9SBard Liao .channels_min = 1, 648e81d47e9SBard Liao .channels_max = 8, 649e81d47e9SBard Liao }, 650fdd961e3SKeyon Jie }, 651fdd961e3SKeyon Jie { 652fdd961e3SKeyon Jie .name = "DMIC01 Pin", 653e81d47e9SBard Liao .capture = { 654e81d47e9SBard Liao .channels_min = 1, 655e81d47e9SBard Liao .channels_max = 4, 656e81d47e9SBard Liao }, 657fdd961e3SKeyon Jie }, 658fdd961e3SKeyon Jie { 659fdd961e3SKeyon Jie .name = "DMIC16k Pin", 660e81d47e9SBard Liao .capture = { 661e81d47e9SBard Liao .channels_min = 1, 662e81d47e9SBard Liao .channels_max = 4, 663e81d47e9SBard Liao }, 664fdd961e3SKeyon Jie }, 665a4203256SPierre-Louis Bossart #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) 666fdd961e3SKeyon Jie { 667fdd961e3SKeyon Jie .name = "iDisp1 Pin", 668e81d47e9SBard Liao .playback = { 669e81d47e9SBard Liao .channels_min = 1, 670e81d47e9SBard Liao .channels_max = 8, 671e81d47e9SBard Liao }, 672fdd961e3SKeyon Jie }, 673fdd961e3SKeyon Jie { 674fdd961e3SKeyon Jie .name = "iDisp2 Pin", 675e81d47e9SBard Liao .playback = { 676e81d47e9SBard Liao .channels_min = 1, 677e81d47e9SBard Liao .channels_max = 8, 678e81d47e9SBard Liao }, 679fdd961e3SKeyon Jie }, 680fdd961e3SKeyon Jie { 681fdd961e3SKeyon Jie .name = "iDisp3 Pin", 682e81d47e9SBard Liao .playback = { 683e81d47e9SBard Liao .channels_min = 1, 684e81d47e9SBard Liao .channels_max = 8, 685e81d47e9SBard Liao }, 686fdd961e3SKeyon Jie }, 687fdd961e3SKeyon Jie { 688e68d6696SSathyanarayana Nujella .name = "iDisp4 Pin", 689e81d47e9SBard Liao .playback = { 690e81d47e9SBard Liao .channels_min = 1, 691e81d47e9SBard Liao .channels_max = 8, 692e81d47e9SBard Liao }, 693e68d6696SSathyanarayana Nujella }, 694e68d6696SSathyanarayana Nujella { 695fdd961e3SKeyon Jie .name = "Analog CPU DAI", 696e81d47e9SBard Liao .playback = { 697e81d47e9SBard Liao .channels_min = 1, 698e81d47e9SBard Liao .channels_max = 16, 699e81d47e9SBard Liao }, 700e81d47e9SBard Liao .capture = { 701e81d47e9SBard Liao .channels_min = 1, 702e81d47e9SBard Liao .channels_max = 16, 703e81d47e9SBard Liao }, 704fdd961e3SKeyon Jie }, 705fdd961e3SKeyon Jie { 706fdd961e3SKeyon Jie .name = "Digital CPU DAI", 707e81d47e9SBard Liao .playback = { 708e81d47e9SBard Liao .channels_min = 1, 709e81d47e9SBard Liao .channels_max = 16, 710e81d47e9SBard Liao }, 711e81d47e9SBard Liao .capture = { 712e81d47e9SBard Liao .channels_min = 1, 713e81d47e9SBard Liao .channels_max = 16, 714e81d47e9SBard Liao }, 715fdd961e3SKeyon Jie }, 716fdd961e3SKeyon Jie { 717fdd961e3SKeyon Jie .name = "Alt Analog CPU DAI", 718e81d47e9SBard Liao .playback = { 719e81d47e9SBard Liao .channels_min = 1, 720e81d47e9SBard Liao .channels_max = 16, 721e81d47e9SBard Liao }, 722e81d47e9SBard Liao .capture = { 723e81d47e9SBard Liao .channels_min = 1, 724e81d47e9SBard Liao .channels_max = 16, 725e81d47e9SBard Liao }, 726fdd961e3SKeyon Jie }, 727fdd961e3SKeyon Jie #endif 728fdd961e3SKeyon Jie }; 729f09e9284SPierre-Louis Bossart 730f09e9284SPierre-Louis Bossart int hda_dsp_dais_suspend(struct snd_sof_dev *sdev) 731f09e9284SPierre-Louis Bossart { 732f09e9284SPierre-Louis Bossart /* 733f09e9284SPierre-Louis Bossart * In the corner case where a SUSPEND happens during a PAUSE, the ALSA core 734f09e9284SPierre-Louis Bossart * does not throw the TRIGGER_SUSPEND. This leaves the DAIs in an unbalanced state. 735f09e9284SPierre-Louis Bossart * Since the component suspend is called last, we can trap this corner case 736f09e9284SPierre-Louis Bossart * and force the DAIs to release their resources. 737f09e9284SPierre-Louis Bossart */ 738a4203256SPierre-Louis Bossart #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) 739f09e9284SPierre-Louis Bossart int ret; 740f09e9284SPierre-Louis Bossart 741f09e9284SPierre-Louis Bossart ret = hda_dai_suspend(sof_to_bus(sdev)); 742f09e9284SPierre-Louis Bossart if (ret < 0) 743f09e9284SPierre-Louis Bossart return ret; 744f09e9284SPierre-Louis Bossart #endif 745f09e9284SPierre-Louis Bossart 746f09e9284SPierre-Louis Bossart return 0; 747f09e9284SPierre-Louis Bossart } 748