18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
28c2ecf20Sopenharmony_ci//
38c2ecf20Sopenharmony_ci// This file is provided under a dual BSD/GPLv2 license.  When using or
48c2ecf20Sopenharmony_ci// redistributing this file, you may do so under either license.
58c2ecf20Sopenharmony_ci//
68c2ecf20Sopenharmony_ci// Copyright(c) 2019-2020 Intel Corporation. All rights reserved.
78c2ecf20Sopenharmony_ci//
88c2ecf20Sopenharmony_ci// Author: Cezary Rojewski <cezary.rojewski@intel.com>
98c2ecf20Sopenharmony_ci//
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <sound/hdaudio_ext.h>
128c2ecf20Sopenharmony_ci#include <sound/soc.h>
138c2ecf20Sopenharmony_ci#include "../sof-priv.h"
148c2ecf20Sopenharmony_ci#include "hda.h"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_cistatic inline struct hdac_ext_stream *
178c2ecf20Sopenharmony_cihda_compr_get_stream(struct snd_compr_stream *cstream)
188c2ecf20Sopenharmony_ci{
198c2ecf20Sopenharmony_ci	return cstream->runtime->private_data;
208c2ecf20Sopenharmony_ci}
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ciint hda_probe_compr_assign(struct snd_sof_dev *sdev,
238c2ecf20Sopenharmony_ci			   struct snd_compr_stream *cstream,
248c2ecf20Sopenharmony_ci			   struct snd_soc_dai *dai)
258c2ecf20Sopenharmony_ci{
268c2ecf20Sopenharmony_ci	struct hdac_ext_stream *stream;
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci	stream = hda_dsp_stream_get(sdev, cstream->direction);
298c2ecf20Sopenharmony_ci	if (!stream)
308c2ecf20Sopenharmony_ci		return -EBUSY;
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	hdac_stream(stream)->curr_pos = 0;
338c2ecf20Sopenharmony_ci	hdac_stream(stream)->cstream = cstream;
348c2ecf20Sopenharmony_ci	cstream->runtime->private_data = stream;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	return hdac_stream(stream)->stream_tag;
378c2ecf20Sopenharmony_ci}
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ciint hda_probe_compr_free(struct snd_sof_dev *sdev,
408c2ecf20Sopenharmony_ci			 struct snd_compr_stream *cstream,
418c2ecf20Sopenharmony_ci			 struct snd_soc_dai *dai)
428c2ecf20Sopenharmony_ci{
438c2ecf20Sopenharmony_ci	struct hdac_ext_stream *stream = hda_compr_get_stream(cstream);
448c2ecf20Sopenharmony_ci	int ret;
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	ret = hda_dsp_stream_put(sdev, cstream->direction,
478c2ecf20Sopenharmony_ci				 hdac_stream(stream)->stream_tag);
488c2ecf20Sopenharmony_ci	if (ret < 0) {
498c2ecf20Sopenharmony_ci		dev_dbg(sdev->dev, "stream put failed: %d\n", ret);
508c2ecf20Sopenharmony_ci		return ret;
518c2ecf20Sopenharmony_ci	}
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	hdac_stream(stream)->cstream = NULL;
548c2ecf20Sopenharmony_ci	cstream->runtime->private_data = NULL;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	return 0;
578c2ecf20Sopenharmony_ci}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ciint hda_probe_compr_set_params(struct snd_sof_dev *sdev,
608c2ecf20Sopenharmony_ci			       struct snd_compr_stream *cstream,
618c2ecf20Sopenharmony_ci			       struct snd_compr_params *params,
628c2ecf20Sopenharmony_ci			       struct snd_soc_dai *dai)
638c2ecf20Sopenharmony_ci{
648c2ecf20Sopenharmony_ci	struct hdac_ext_stream *stream = hda_compr_get_stream(cstream);
658c2ecf20Sopenharmony_ci	struct hdac_stream *hstream = hdac_stream(stream);
668c2ecf20Sopenharmony_ci	struct snd_dma_buffer *dmab;
678c2ecf20Sopenharmony_ci	u32 bits, rate;
688c2ecf20Sopenharmony_ci	int bps, ret;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	dmab = cstream->runtime->dma_buffer_p;
718c2ecf20Sopenharmony_ci	/* compr params do not store bit depth, default to S32_LE */
728c2ecf20Sopenharmony_ci	bps = snd_pcm_format_physical_width(SNDRV_PCM_FORMAT_S32_LE);
738c2ecf20Sopenharmony_ci	if (bps < 0)
748c2ecf20Sopenharmony_ci		return bps;
758c2ecf20Sopenharmony_ci	bits = hda_dsp_get_bits(sdev, bps);
768c2ecf20Sopenharmony_ci	rate = hda_dsp_get_mult_div(sdev, params->codec.sample_rate);
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	hstream->format_val = rate | bits | (params->codec.ch_out - 1);
798c2ecf20Sopenharmony_ci	hstream->bufsize = cstream->runtime->buffer_size;
808c2ecf20Sopenharmony_ci	hstream->period_bytes = cstream->runtime->fragment_size;
818c2ecf20Sopenharmony_ci	hstream->no_period_wakeup = 0;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	ret = hda_dsp_stream_hw_params(sdev, stream, dmab, NULL);
848c2ecf20Sopenharmony_ci	if (ret < 0) {
858c2ecf20Sopenharmony_ci		dev_err(sdev->dev, "error: hdac prepare failed: %x\n", ret);
868c2ecf20Sopenharmony_ci		return ret;
878c2ecf20Sopenharmony_ci	}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	return 0;
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ciint hda_probe_compr_trigger(struct snd_sof_dev *sdev,
938c2ecf20Sopenharmony_ci			    struct snd_compr_stream *cstream, int cmd,
948c2ecf20Sopenharmony_ci			    struct snd_soc_dai *dai)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	struct hdac_ext_stream *stream = hda_compr_get_stream(cstream);
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	return hda_dsp_stream_trigger(sdev, stream, cmd);
998c2ecf20Sopenharmony_ci}
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ciint hda_probe_compr_pointer(struct snd_sof_dev *sdev,
1028c2ecf20Sopenharmony_ci			    struct snd_compr_stream *cstream,
1038c2ecf20Sopenharmony_ci			    struct snd_compr_tstamp *tstamp,
1048c2ecf20Sopenharmony_ci			    struct snd_soc_dai *dai)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci	struct hdac_ext_stream *stream = hda_compr_get_stream(cstream);
1078c2ecf20Sopenharmony_ci	struct snd_soc_pcm_stream *pstream;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	pstream = &dai->driver->capture;
1108c2ecf20Sopenharmony_ci	tstamp->copied_total = hdac_stream(stream)->curr_pos;
1118c2ecf20Sopenharmony_ci	tstamp->sampling_rate = snd_pcm_rate_bit_to_rate(pstream->rates);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	return 0;
1148c2ecf20Sopenharmony_ci}
115