brintos

brintos / linux-shallow public Read only

0
0
Text · 19.0 KiB · 92681ca Raw
661 lines · c
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 or4// redistributing this file, you may do so under either license.5//6// Copyright(c) 2022 Intel Corporation7 8#include <sound/pcm_params.h>9#include <sound/hdaudio_ext.h>10#include <sound/hda_register.h>11#include <sound/hda-mlink.h>12#include <sound/sof/ipc4/header.h>13#include <uapi/sound/sof/header.h>14#include "../ipc4-priv.h"15#include "../ipc4-topology.h"16#include "../sof-priv.h"17#include "../sof-audio.h"18#include "hda.h"19 20/* These ops are only applicable for the HDA DAI's in their current form */21#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK)22/*23 * This function checks if the host dma channel corresponding24 * to the link DMA stream_tag argument is assigned to one25 * of the FEs connected to the BE DAI.26 */27static bool hda_check_fes(struct snd_soc_pcm_runtime *rtd,28			  int dir, int stream_tag)29{30	struct snd_pcm_substream *fe_substream;31	struct hdac_stream *fe_hstream;32	struct snd_soc_dpcm *dpcm;33 34	for_each_dpcm_fe(rtd, dir, dpcm) {35		fe_substream = snd_soc_dpcm_get_substream(dpcm->fe, dir);36		fe_hstream = fe_substream->runtime->private_data;37		if (fe_hstream->stream_tag == stream_tag)38			return true;39	}40 41	return false;42}43 44static struct hdac_ext_stream *45hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream)46{47	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);48	struct sof_intel_hda_stream *hda_stream;49	const struct sof_intel_dsp_desc *chip;50	struct snd_sof_dev *sdev;51	struct hdac_ext_stream *res = NULL;52	struct hdac_stream *hstream = NULL;53 54	int stream_dir = substream->stream;55 56	if (!bus->ppcap) {57		dev_err(bus->dev, "stream type not supported\n");58		return NULL;59	}60 61	spin_lock_irq(&bus->reg_lock);62	list_for_each_entry(hstream, &bus->stream_list, list) {63		struct hdac_ext_stream *hext_stream =64			stream_to_hdac_ext_stream(hstream);65		if (hstream->direction != substream->stream)66			continue;67 68		hda_stream = hstream_to_sof_hda_stream(hext_stream);69		sdev = hda_stream->sdev;70		chip = get_chip_info(sdev->pdata);71 72		/* check if link is available */73		if (!hext_stream->link_locked) {74			/*75			 * choose the first available link for platforms that do not have the76			 * PROCEN_FMT_QUIRK set.77			 */78			if (!(chip->quirks & SOF_INTEL_PROCEN_FMT_QUIRK)) {79				res = hext_stream;80				break;81			}82 83			if (hstream->opened) {84				/*85				 * check if the stream tag matches the stream86				 * tag of one of the connected FEs87				 */88				if (hda_check_fes(rtd, stream_dir,89						  hstream->stream_tag)) {90					res = hext_stream;91					break;92				}93			} else {94				res = hext_stream;95 96				/*97				 * This must be a hostless stream.98				 * So reserve the host DMA channel.99				 */100				hda_stream->host_reserved = 1;101				break;102			}103		}104	}105 106	if (res) {107		/* Make sure that host and link DMA is decoupled. */108		snd_hdac_ext_stream_decouple_locked(bus, res, true);109 110		res->link_locked = 1;111		res->link_substream = substream;112	}113	spin_unlock_irq(&bus->reg_lock);114 115	return res;116}117 118static struct hdac_ext_stream *hda_get_hext_stream(struct snd_sof_dev *sdev,119						   struct snd_soc_dai *cpu_dai,120						   struct snd_pcm_substream *substream)121{122	return snd_soc_dai_get_dma_data(cpu_dai, substream);123}124 125static struct hdac_ext_stream *hda_ipc4_get_hext_stream(struct snd_sof_dev *sdev,126							struct snd_soc_dai *cpu_dai,127							struct snd_pcm_substream *substream)128{129	struct snd_sof_widget *pipe_widget;130	struct sof_ipc4_pipeline *pipeline;131	struct snd_sof_widget *swidget;132	struct snd_soc_dapm_widget *w;133 134	w = snd_soc_dai_get_widget(cpu_dai, substream->stream);135	swidget = w->dobj.private;136	pipe_widget = swidget->spipe->pipe_widget;137	pipeline = pipe_widget->private;138 139	/* mark pipeline so that it can be skipped during FE trigger */140	pipeline->skip_during_fe_trigger = true;141 142	return snd_soc_dai_get_dma_data(cpu_dai, substream);143}144 145static struct hdac_ext_stream *hda_assign_hext_stream(struct snd_sof_dev *sdev,146						      struct snd_soc_dai *cpu_dai,147						      struct snd_pcm_substream *substream)148{149	struct hdac_ext_stream *hext_stream;150 151	hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream);152	if (!hext_stream)153		return NULL;154 155	snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)hext_stream);156 157	return hext_stream;158}159 160static void hda_release_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,161				    struct snd_pcm_substream *substream)162{163	struct hdac_ext_stream *hext_stream = hda_get_hext_stream(sdev, cpu_dai, substream);164 165	snd_soc_dai_set_dma_data(cpu_dai, substream, NULL);166	snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK);167}168 169static void hda_setup_hext_stream(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream,170				  unsigned int format_val)171{172	snd_hdac_ext_stream_setup(hext_stream, format_val);173}174 175static void hda_reset_hext_stream(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream)176{177	snd_hdac_ext_stream_reset(hext_stream);178}179 180static void hda_codec_dai_set_stream(struct snd_sof_dev *sdev,181				     struct snd_pcm_substream *substream,182				     struct hdac_stream *hstream)183{184	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);185	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);186 187	/* set the hdac_stream in the codec dai */188	snd_soc_dai_set_stream(codec_dai, hstream, substream->stream);189}190 191static unsigned int hda_calc_stream_format(struct snd_sof_dev *sdev,192					   struct snd_pcm_substream *substream,193					   struct snd_pcm_hw_params *params)194{195	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);196	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);197	unsigned int link_bps;198	unsigned int format_val;199	unsigned int bits;200 201	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)202		link_bps = codec_dai->driver->playback.sig_bits;203	else204		link_bps = codec_dai->driver->capture.sig_bits;205 206	bits = snd_hdac_stream_format_bits(params_format(params), SNDRV_PCM_SUBFORMAT_STD,207					   link_bps);208	format_val = snd_hdac_stream_format(params_channels(params), bits, params_rate(params));209 210	dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val,211		params_rate(params), params_channels(params), params_format(params));212 213	return format_val;214}215 216static struct hdac_ext_link *hda_get_hlink(struct snd_sof_dev *sdev,217					   struct snd_pcm_substream *substream)218{219	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);220	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);221	struct hdac_bus *bus = sof_to_bus(sdev);222 223	return snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name);224}225 226static unsigned int generic_calc_stream_format(struct snd_sof_dev *sdev,227					       struct snd_pcm_substream *substream,228					       struct snd_pcm_hw_params *params)229{230	unsigned int format_val;231	unsigned int bits;232 233	bits = snd_hdac_stream_format_bits(params_format(params), SNDRV_PCM_SUBFORMAT_STD,234					   params_physical_width(params));235	format_val = snd_hdac_stream_format(params_channels(params), bits, params_rate(params));236 237	dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val,238		params_rate(params), params_channels(params), params_format(params));239 240	return format_val;241}242 243static unsigned int dmic_calc_stream_format(struct snd_sof_dev *sdev,244					    struct snd_pcm_substream *substream,245					    struct snd_pcm_hw_params *params)246{247	unsigned int format_val;248	snd_pcm_format_t format;249	unsigned int channels;250	unsigned int width;251	unsigned int bits;252 253	channels = params_channels(params);254	format = params_format(params);255	width = params_physical_width(params);256 257	if (format == SNDRV_PCM_FORMAT_S16_LE) {258		format = SNDRV_PCM_FORMAT_S32_LE;259		channels /= 2;260		width = 32;261	}262 263	bits = snd_hdac_stream_format_bits(format, SNDRV_PCM_SUBFORMAT_STD, width);264	format_val = snd_hdac_stream_format(channels, bits, params_rate(params));265 266	dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val,267		params_rate(params), channels, format);268 269	return format_val;270}271 272static struct hdac_ext_link *ssp_get_hlink(struct snd_sof_dev *sdev,273					   struct snd_pcm_substream *substream)274{275	struct hdac_bus *bus = sof_to_bus(sdev);276 277	return hdac_bus_eml_ssp_get_hlink(bus);278}279 280static struct hdac_ext_link *dmic_get_hlink(struct snd_sof_dev *sdev,281					    struct snd_pcm_substream *substream)282{283	struct hdac_bus *bus = sof_to_bus(sdev);284 285	return hdac_bus_eml_dmic_get_hlink(bus);286}287 288static struct hdac_ext_link *sdw_get_hlink(struct snd_sof_dev *sdev,289					   struct snd_pcm_substream *substream)290{291	struct hdac_bus *bus = sof_to_bus(sdev);292 293	return hdac_bus_eml_sdw_get_hlink(bus);294}295 296static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,297				struct snd_pcm_substream *substream, int cmd)298{299	struct sof_ipc4_fw_data *ipc4_data = sdev->private;300	struct snd_sof_widget *pipe_widget;301	struct sof_ipc4_pipeline *pipeline;302	struct snd_sof_widget *swidget;303	struct snd_soc_dapm_widget *w;304	int ret = 0;305 306	w = snd_soc_dai_get_widget(cpu_dai, substream->stream);307	swidget = w->dobj.private;308	pipe_widget = swidget->spipe->pipe_widget;309	pipeline = pipe_widget->private;310 311	if (pipe_widget->instance_id < 0)312		return 0;313 314	mutex_lock(&ipc4_data->pipeline_state_mutex);315 316	switch (cmd) {317	case SNDRV_PCM_TRIGGER_START:318	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:319		break;320	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:321	case SNDRV_PCM_TRIGGER_SUSPEND:322	case SNDRV_PCM_TRIGGER_STOP:323		ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,324						  SOF_IPC4_PIPE_PAUSED);325		if (ret < 0)326			goto out;327 328		pipeline->state = SOF_IPC4_PIPE_PAUSED;329		break;330	default:331		dev_err(sdev->dev, "unknown trigger command %d\n", cmd);332		ret = -EINVAL;333	}334out:335	mutex_unlock(&ipc4_data->pipeline_state_mutex);336	return ret;337}338 339static int hda_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,340		       struct snd_pcm_substream *substream, int cmd)341{342	struct hdac_ext_stream *hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream);343 344	switch (cmd) {345	case SNDRV_PCM_TRIGGER_START:346	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:347		snd_hdac_ext_stream_start(hext_stream);348		break;349	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:350		/*351		 * Save the LLP registers since in case of PAUSE the LLP352		 * register are not reset to 0, the delay calculation will use353		 * the saved offsets for compensating the delay calculation.354		 */355		hext_stream->pplcllpl = readl(hext_stream->pplc_addr + AZX_REG_PPLCLLPL);356		hext_stream->pplcllpu = readl(hext_stream->pplc_addr + AZX_REG_PPLCLLPU);357		snd_hdac_ext_stream_clear(hext_stream);358		break;359	case SNDRV_PCM_TRIGGER_SUSPEND:360	case SNDRV_PCM_TRIGGER_STOP:361		hext_stream->pplcllpl = 0;362		hext_stream->pplcllpu = 0;363		snd_hdac_ext_stream_clear(hext_stream);364		break;365	default:366		dev_err(sdev->dev, "unknown trigger command %d\n", cmd);367		return -EINVAL;368	}369 370	return 0;371}372 373static int hda_ipc4_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,374				 struct snd_pcm_substream *substream, int cmd)375{376	struct sof_ipc4_fw_data *ipc4_data = sdev->private;377	struct snd_sof_widget *pipe_widget;378	struct sof_ipc4_pipeline *pipeline;379	struct snd_sof_widget *swidget;380	struct snd_soc_dapm_widget *w;381	int ret = 0;382 383	w = snd_soc_dai_get_widget(cpu_dai, substream->stream);384	swidget = w->dobj.private;385	pipe_widget = swidget->spipe->pipe_widget;386	pipeline = pipe_widget->private;387 388	if (pipe_widget->instance_id < 0)389		return 0;390 391	mutex_lock(&ipc4_data->pipeline_state_mutex);392 393	switch (cmd) {394	case SNDRV_PCM_TRIGGER_START:395		if (pipeline->state != SOF_IPC4_PIPE_PAUSED) {396			ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,397							  SOF_IPC4_PIPE_PAUSED);398			if (ret < 0)399				goto out;400			pipeline->state = SOF_IPC4_PIPE_PAUSED;401		}402 403		ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,404						  SOF_IPC4_PIPE_RUNNING);405		if (ret < 0)406			goto out;407		pipeline->state = SOF_IPC4_PIPE_RUNNING;408		swidget->spipe->started_count++;409		break;410	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:411		ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,412						  SOF_IPC4_PIPE_RUNNING);413		if (ret < 0)414			goto out;415		pipeline->state = SOF_IPC4_PIPE_RUNNING;416		break;417	case SNDRV_PCM_TRIGGER_SUSPEND:418	case SNDRV_PCM_TRIGGER_STOP:419		/*420		 * STOP/SUSPEND trigger is invoked only once when all users of this pipeline have421		 * been stopped. So, clear the started_count so that the pipeline can be reset422		 */423		swidget->spipe->started_count = 0;424		break;425	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:426		break;427	default:428		dev_err(sdev->dev, "unknown trigger command %d\n", cmd);429		ret = -EINVAL;430		break;431	}432out:433	mutex_unlock(&ipc4_data->pipeline_state_mutex);434	return ret;435}436 437static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = {438	.get_hext_stream = hda_ipc4_get_hext_stream,439	.assign_hext_stream = hda_assign_hext_stream,440	.release_hext_stream = hda_release_hext_stream,441	.setup_hext_stream = hda_setup_hext_stream,442	.reset_hext_stream = hda_reset_hext_stream,443	.pre_trigger = hda_ipc4_pre_trigger,444	.trigger = hda_trigger,445	.post_trigger = hda_ipc4_post_trigger,446	.codec_dai_set_stream = hda_codec_dai_set_stream,447	.calc_stream_format = hda_calc_stream_format,448	.get_hlink = hda_get_hlink,449};450 451static const struct hda_dai_widget_dma_ops ssp_ipc4_dma_ops = {452	.get_hext_stream = hda_ipc4_get_hext_stream,453	.assign_hext_stream = hda_assign_hext_stream,454	.release_hext_stream = hda_release_hext_stream,455	.setup_hext_stream = hda_setup_hext_stream,456	.reset_hext_stream = hda_reset_hext_stream,457	.pre_trigger = hda_ipc4_pre_trigger,458	.trigger = hda_trigger,459	.post_trigger = hda_ipc4_post_trigger,460	.calc_stream_format = generic_calc_stream_format,461	.get_hlink = ssp_get_hlink,462};463 464static const struct hda_dai_widget_dma_ops dmic_ipc4_dma_ops = {465	.get_hext_stream = hda_ipc4_get_hext_stream,466	.assign_hext_stream = hda_assign_hext_stream,467	.release_hext_stream = hda_release_hext_stream,468	.setup_hext_stream = hda_setup_hext_stream,469	.reset_hext_stream = hda_reset_hext_stream,470	.pre_trigger = hda_ipc4_pre_trigger,471	.trigger = hda_trigger,472	.post_trigger = hda_ipc4_post_trigger,473	.calc_stream_format = dmic_calc_stream_format,474	.get_hlink = dmic_get_hlink,475};476 477static const struct hda_dai_widget_dma_ops sdw_ipc4_dma_ops = {478	.get_hext_stream = hda_ipc4_get_hext_stream,479	.assign_hext_stream = hda_assign_hext_stream,480	.release_hext_stream = hda_release_hext_stream,481	.setup_hext_stream = hda_setup_hext_stream,482	.reset_hext_stream = hda_reset_hext_stream,483	.pre_trigger = hda_ipc4_pre_trigger,484	.trigger = hda_trigger,485	.post_trigger = hda_ipc4_post_trigger,486	.calc_stream_format = generic_calc_stream_format,487	.get_hlink = sdw_get_hlink,488};489 490static const struct hda_dai_widget_dma_ops hda_ipc4_chain_dma_ops = {491	.get_hext_stream = hda_get_hext_stream,492	.assign_hext_stream = hda_assign_hext_stream,493	.release_hext_stream = hda_release_hext_stream,494	.setup_hext_stream = hda_setup_hext_stream,495	.reset_hext_stream = hda_reset_hext_stream,496	.trigger = hda_trigger,497	.codec_dai_set_stream = hda_codec_dai_set_stream,498	.calc_stream_format = hda_calc_stream_format,499	.get_hlink = hda_get_hlink,500};501 502static const struct hda_dai_widget_dma_ops sdw_ipc4_chain_dma_ops = {503	.get_hext_stream = hda_get_hext_stream,504	.assign_hext_stream = hda_assign_hext_stream,505	.release_hext_stream = hda_release_hext_stream,506	.setup_hext_stream = hda_setup_hext_stream,507	.reset_hext_stream = hda_reset_hext_stream,508	.trigger = hda_trigger,509	.calc_stream_format = generic_calc_stream_format,510	.get_hlink = sdw_get_hlink,511};512 513static int hda_ipc3_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,514				 struct snd_pcm_substream *substream, int cmd)515{516	struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);517 518	switch (cmd) {519	case SNDRV_PCM_TRIGGER_SUSPEND:520	case SNDRV_PCM_TRIGGER_STOP:521	{522		struct snd_sof_dai_config_data data = { 0 };523		int ret;524 525		data.dai_data = DMA_CHAN_INVALID;526		ret = hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_HW_FREE, &data);527		if (ret < 0)528			return ret;529 530		break;531	}532	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:533		return hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_PAUSE, NULL);534	default:535		break;536	}537 538	return 0;539}540 541static const struct hda_dai_widget_dma_ops hda_ipc3_dma_ops = {542	.get_hext_stream = hda_get_hext_stream,543	.assign_hext_stream = hda_assign_hext_stream,544	.release_hext_stream = hda_release_hext_stream,545	.setup_hext_stream = hda_setup_hext_stream,546	.reset_hext_stream = hda_reset_hext_stream,547	.trigger = hda_trigger,548	.post_trigger = hda_ipc3_post_trigger,549	.codec_dai_set_stream = hda_codec_dai_set_stream,550	.calc_stream_format = hda_calc_stream_format,551	.get_hlink = hda_get_hlink,552};553 554static struct hdac_ext_stream *555hda_dspless_get_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,556			    struct snd_pcm_substream *substream)557{558	struct hdac_stream *hstream = substream->runtime->private_data;559 560	return stream_to_hdac_ext_stream(hstream);561}562 563static void hda_dspless_setup_hext_stream(struct snd_sof_dev *sdev,564					  struct hdac_ext_stream *hext_stream,565					  unsigned int format_val)566{567	/*568	 * Save the format_val which was adjusted by the maxbps of the codec.569	 * This information is not available on the FE side since there we are570	 * using dummy_codec.571	 */572	hext_stream->hstream.format_val = format_val;573}574 575static const struct hda_dai_widget_dma_ops hda_dspless_dma_ops = {576	.get_hext_stream = hda_dspless_get_hext_stream,577	.setup_hext_stream = hda_dspless_setup_hext_stream,578	.codec_dai_set_stream = hda_codec_dai_set_stream,579	.calc_stream_format = hda_calc_stream_format,580	.get_hlink = hda_get_hlink,581};582 583static const struct hda_dai_widget_dma_ops sdw_dspless_dma_ops = {584	.get_hext_stream = hda_dspless_get_hext_stream,585	.setup_hext_stream = hda_dspless_setup_hext_stream,586	.calc_stream_format = generic_calc_stream_format,587	.get_hlink = sdw_get_hlink,588};589 590#endif591 592const struct hda_dai_widget_dma_ops *593hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)594{595#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK)596	struct snd_sof_dai *sdai;597	const struct sof_intel_dsp_desc *chip;598 599	chip = get_chip_info(sdev->pdata);600	sdai = swidget->private;601 602	if (sdev->dspless_mode_selected) {603		switch (sdai->type) {604		case SOF_DAI_INTEL_HDA:605			return &hda_dspless_dma_ops;606		case SOF_DAI_INTEL_ALH:607			if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)608				return NULL;609			return &sdw_dspless_dma_ops;610		default:611			return NULL;612		}613	}614 615	switch (sdev->pdata->ipc_type) {616	case SOF_IPC_TYPE_3:617	{618		struct sof_dai_private_data *private = sdai->private;619 620		if (private->dai_config->type == SOF_DAI_INTEL_HDA)621			return &hda_ipc3_dma_ops;622		break;623	}624	case SOF_IPC_TYPE_4:625	{626		struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;627		struct sof_ipc4_pipeline *pipeline = pipe_widget->private;628 629		switch (sdai->type) {630		case SOF_DAI_INTEL_HDA:631			if (pipeline->use_chain_dma)632				return &hda_ipc4_chain_dma_ops;633 634			return &hda_ipc4_dma_ops;635		case SOF_DAI_INTEL_SSP:636			if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)637				return NULL;638			return &ssp_ipc4_dma_ops;639		case SOF_DAI_INTEL_DMIC:640			if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)641				return NULL;642			return &dmic_ipc4_dma_ops;643		case SOF_DAI_INTEL_ALH:644			if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)645				return NULL;646			if (pipeline->use_chain_dma)647				return &sdw_ipc4_chain_dma_ops;648			return &sdw_ipc4_dma_ops;649 650		default:651			break;652		}653		break;654	}655	default:656		break;657	}658#endif659	return NULL;660}661