cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sst_drv_interface.c (18688B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 *  sst_drv_interface.c - Intel SST Driver for audio engine
      4 *
      5 *  Copyright (C) 2008-14 Intel Corp
      6 *  Authors:	Vinod Koul <vinod.koul@intel.com>
      7 *		Harsha Priya <priya.harsha@intel.com>
      8 *		Dharageswari R <dharageswari.r@intel.com)
      9 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     10 *
     11 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     12 */
     13#include <linux/delay.h>
     14#include <linux/pci.h>
     15#include <linux/fs.h>
     16#include <linux/firmware.h>
     17#include <linux/pm_runtime.h>
     18#include <linux/pm_qos.h>
     19#include <linux/math64.h>
     20#include <sound/core.h>
     21#include <sound/pcm.h>
     22#include <sound/soc.h>
     23#include <sound/compress_driver.h>
     24#include <asm/platform_sst_audio.h>
     25#include "../sst-mfld-platform.h"
     26#include "sst.h"
     27
     28#define NUM_CODEC 2
     29#define MIN_FRAGMENT 2
     30#define MAX_FRAGMENT 4
     31#define MIN_FRAGMENT_SIZE (50 * 1024)
     32#define MAX_FRAGMENT_SIZE (1024 * 1024)
     33#define SST_GET_BYTES_PER_SAMPLE(pcm_wd_sz)  (((pcm_wd_sz + 15) >> 4) << 1)
     34#ifdef CONFIG_PM
     35#define GET_USAGE_COUNT(dev) (atomic_read(&dev->power.usage_count))
     36#else
     37#define GET_USAGE_COUNT(dev) 1
     38#endif
     39
     40int free_stream_context(struct intel_sst_drv *ctx, unsigned int str_id)
     41{
     42	struct stream_info *stream;
     43	int ret = 0;
     44
     45	stream = get_stream_info(ctx, str_id);
     46	if (stream) {
     47		/* str_id is valid, so stream is alloacted */
     48		ret = sst_free_stream(ctx, str_id);
     49		if (ret)
     50			sst_clean_stream(&ctx->streams[str_id]);
     51		return ret;
     52	} else {
     53		dev_err(ctx->dev, "we tried to free stream context %d which was freed!!!\n", str_id);
     54	}
     55	return ret;
     56}
     57
     58int sst_get_stream_allocated(struct intel_sst_drv *ctx,
     59	struct snd_sst_params *str_param,
     60	struct snd_sst_lib_download **lib_dnld)
     61{
     62	int retval;
     63
     64	retval = ctx->ops->alloc_stream(ctx, str_param);
     65	if (retval > 0)
     66		dev_dbg(ctx->dev, "Stream allocated %d\n", retval);
     67	return retval;
     68
     69}
     70
     71/*
     72 * sst_get_sfreq - this function returns the frequency of the stream
     73 *
     74 * @str_param : stream params
     75 */
     76int sst_get_sfreq(struct snd_sst_params *str_param)
     77{
     78	switch (str_param->codec) {
     79	case SST_CODEC_TYPE_PCM:
     80		return str_param->sparams.uc.pcm_params.sfreq;
     81	case SST_CODEC_TYPE_AAC:
     82		return str_param->sparams.uc.aac_params.externalsr;
     83	case SST_CODEC_TYPE_MP3:
     84		return 0;
     85	default:
     86		return -EINVAL;
     87	}
     88}
     89
     90/*
     91 * sst_get_num_channel - get number of channels for the stream
     92 *
     93 * @str_param : stream params
     94 */
     95int sst_get_num_channel(struct snd_sst_params *str_param)
     96{
     97	switch (str_param->codec) {
     98	case SST_CODEC_TYPE_PCM:
     99		return str_param->sparams.uc.pcm_params.num_chan;
    100	case SST_CODEC_TYPE_MP3:
    101		return str_param->sparams.uc.mp3_params.num_chan;
    102	case SST_CODEC_TYPE_AAC:
    103		return str_param->sparams.uc.aac_params.num_chan;
    104	default:
    105		return -EINVAL;
    106	}
    107}
    108
    109/*
    110 * sst_get_stream - this function prepares for stream allocation
    111 *
    112 * @str_param : stream param
    113 */
    114int sst_get_stream(struct intel_sst_drv *ctx,
    115			struct snd_sst_params *str_param)
    116{
    117	int retval;
    118	struct stream_info *str_info;
    119
    120	/* stream is not allocated, we are allocating */
    121	retval = ctx->ops->alloc_stream(ctx, str_param);
    122	if (retval <= 0) {
    123		return -EIO;
    124	}
    125	/* store sampling freq */
    126	str_info = &ctx->streams[retval];
    127	str_info->sfreq = sst_get_sfreq(str_param);
    128
    129	return retval;
    130}
    131
    132static int sst_power_control(struct device *dev, bool state)
    133{
    134	struct intel_sst_drv *ctx = dev_get_drvdata(dev);
    135	int ret = 0;
    136	int usage_count = 0;
    137
    138	if (state) {
    139		ret = pm_runtime_resume_and_get(dev);
    140		usage_count = GET_USAGE_COUNT(dev);
    141		dev_dbg(ctx->dev, "Enable: pm usage count: %d\n", usage_count);
    142		if (ret < 0) {
    143			dev_err(ctx->dev, "Runtime get failed with err: %d\n", ret);
    144			return ret;
    145		}
    146		if ((ctx->sst_state == SST_RESET) && (usage_count == 1)) {
    147			ret = sst_load_fw(ctx);
    148			if (ret) {
    149				dev_err(dev, "FW download fail %d\n", ret);
    150				sst_set_fw_state_locked(ctx, SST_RESET);
    151				ret = sst_pm_runtime_put(ctx);
    152			}
    153		}
    154	} else {
    155		usage_count = GET_USAGE_COUNT(dev);
    156		dev_dbg(ctx->dev, "Disable: pm usage count: %d\n", usage_count);
    157		return sst_pm_runtime_put(ctx);
    158	}
    159	return ret;
    160}
    161
    162/*
    163 * sst_open_pcm_stream - Open PCM interface
    164 *
    165 * @str_param: parameters of pcm stream
    166 *
    167 * This function is called by MID sound card driver to open
    168 * a new pcm interface
    169 */
    170static int sst_open_pcm_stream(struct device *dev,
    171		struct snd_sst_params *str_param)
    172{
    173	int retval;
    174	struct intel_sst_drv *ctx = dev_get_drvdata(dev);
    175
    176	if (!str_param)
    177		return -EINVAL;
    178
    179	retval = sst_get_stream(ctx, str_param);
    180	if (retval > 0)
    181		ctx->stream_cnt++;
    182	else
    183		dev_err(ctx->dev, "sst_get_stream returned err %d\n", retval);
    184
    185	return retval;
    186}
    187
    188static int sst_cdev_open(struct device *dev,
    189		struct snd_sst_params *str_params, struct sst_compress_cb *cb)
    190{
    191	int str_id, retval;
    192	struct stream_info *stream;
    193	struct intel_sst_drv *ctx = dev_get_drvdata(dev);
    194
    195	retval = pm_runtime_resume_and_get(ctx->dev);
    196	if (retval < 0)
    197		return retval;
    198
    199	str_id = sst_get_stream(ctx, str_params);
    200	if (str_id > 0) {
    201		dev_dbg(dev, "stream allocated in sst_cdev_open %d\n", str_id);
    202		stream = &ctx->streams[str_id];
    203		stream->compr_cb = cb->compr_cb;
    204		stream->compr_cb_param = cb->param;
    205		stream->drain_notify = cb->drain_notify;
    206		stream->drain_cb_param = cb->drain_cb_param;
    207	} else {
    208		dev_err(dev, "stream encountered error during alloc %d\n", str_id);
    209		str_id = -EINVAL;
    210		sst_pm_runtime_put(ctx);
    211	}
    212	return str_id;
    213}
    214
    215static int sst_cdev_close(struct device *dev, unsigned int str_id)
    216{
    217	int retval;
    218	struct stream_info *stream;
    219	struct intel_sst_drv *ctx = dev_get_drvdata(dev);
    220
    221	stream = get_stream_info(ctx, str_id);
    222	if (!stream) {
    223		dev_err(dev, "stream info is NULL for str %d!!!\n", str_id);
    224		return -EINVAL;
    225	}
    226
    227	retval = sst_free_stream(ctx, str_id);
    228	stream->compr_cb_param = NULL;
    229	stream->compr_cb = NULL;
    230
    231	if (retval)
    232		dev_err(dev, "free stream returned err %d\n", retval);
    233
    234	dev_dbg(dev, "End\n");
    235	return retval;
    236}
    237
    238static int sst_cdev_ack(struct device *dev, unsigned int str_id,
    239		unsigned long bytes)
    240{
    241	struct stream_info *stream;
    242	struct snd_sst_tstamp fw_tstamp = {0,};
    243	int offset;
    244	void __iomem *addr;
    245	struct intel_sst_drv *ctx = dev_get_drvdata(dev);
    246
    247	stream = get_stream_info(ctx, str_id);
    248	if (!stream)
    249		return -EINVAL;
    250
    251	/* update bytes sent */
    252	stream->cumm_bytes += bytes;
    253	dev_dbg(dev, "bytes copied %d inc by %ld\n", stream->cumm_bytes, bytes);
    254
    255	addr =  ((void __iomem *)(ctx->mailbox + ctx->tstamp)) +
    256		(str_id * sizeof(fw_tstamp));
    257
    258	memcpy_fromio(&fw_tstamp, addr, sizeof(fw_tstamp));
    259
    260	fw_tstamp.bytes_copied = stream->cumm_bytes;
    261	dev_dbg(dev, "bytes sent to fw %llu inc by %ld\n",
    262			fw_tstamp.bytes_copied, bytes);
    263
    264	offset =  offsetof(struct snd_sst_tstamp, bytes_copied);
    265	sst_shim_write(addr, offset, fw_tstamp.bytes_copied);
    266	return 0;
    267}
    268
    269static int sst_cdev_set_metadata(struct device *dev,
    270		unsigned int str_id, struct snd_compr_metadata *metadata)
    271{
    272	int retval = 0;
    273	struct stream_info *str_info;
    274	struct intel_sst_drv *ctx = dev_get_drvdata(dev);
    275
    276	dev_dbg(dev, "set metadata for stream %d\n", str_id);
    277
    278	str_info = get_stream_info(ctx, str_id);
    279	if (!str_info)
    280		return -EINVAL;
    281
    282	dev_dbg(dev, "pipe id = %d\n", str_info->pipe_id);
    283	retval = sst_prepare_and_post_msg(ctx, str_info->task_id, IPC_CMD,
    284			IPC_IA_SET_STREAM_PARAMS_MRFLD, str_info->pipe_id,
    285			sizeof(*metadata), metadata, NULL,
    286			true, true, true, false);
    287
    288	return retval;
    289}
    290
    291static int sst_cdev_stream_pause(struct device *dev, unsigned int str_id)
    292{
    293	struct intel_sst_drv *ctx = dev_get_drvdata(dev);
    294
    295	return sst_pause_stream(ctx, str_id);
    296}
    297
    298static int sst_cdev_stream_pause_release(struct device *dev,
    299		unsigned int str_id)
    300{
    301	struct intel_sst_drv *ctx = dev_get_drvdata(dev);
    302
    303	return sst_resume_stream(ctx, str_id);
    304}
    305
    306static int sst_cdev_stream_start(struct device *dev, unsigned int str_id)
    307{
    308	struct stream_info *str_info;
    309	struct intel_sst_drv *ctx = dev_get_drvdata(dev);
    310
    311	str_info = get_stream_info(ctx, str_id);
    312	if (!str_info)
    313		return -EINVAL;
    314	str_info->prev = str_info->status;
    315	str_info->status = STREAM_RUNNING;
    316	return sst_start_stream(ctx, str_id);
    317}
    318
    319static int sst_cdev_stream_drop(struct device *dev, unsigned int str_id)
    320{
    321	struct intel_sst_drv *ctx = dev_get_drvdata(dev);
    322
    323	return sst_drop_stream(ctx, str_id);
    324}
    325
    326static int sst_cdev_stream_drain(struct device *dev, unsigned int str_id)
    327{
    328	struct intel_sst_drv *ctx = dev_get_drvdata(dev);
    329
    330	return sst_drain_stream(ctx, str_id, false);
    331}
    332
    333static int sst_cdev_stream_partial_drain(struct device *dev,
    334		unsigned int str_id)
    335{
    336	struct intel_sst_drv *ctx = dev_get_drvdata(dev);
    337
    338	return sst_drain_stream(ctx, str_id, true);
    339}
    340
    341static int sst_cdev_tstamp(struct device *dev, unsigned int str_id,
    342		struct snd_compr_tstamp *tstamp)
    343{
    344	struct snd_sst_tstamp fw_tstamp = {0,};
    345	struct stream_info *stream;
    346	struct intel_sst_drv *ctx = dev_get_drvdata(dev);
    347	void __iomem *addr;
    348
    349	addr = (void __iomem *)(ctx->mailbox + ctx->tstamp) +
    350		(str_id * sizeof(fw_tstamp));
    351
    352	memcpy_fromio(&fw_tstamp, addr, sizeof(fw_tstamp));
    353
    354	stream = get_stream_info(ctx, str_id);
    355	if (!stream)
    356		return -EINVAL;
    357	dev_dbg(dev, "rb_counter %llu in bytes\n", fw_tstamp.ring_buffer_counter);
    358
    359	tstamp->copied_total = fw_tstamp.ring_buffer_counter;
    360	tstamp->pcm_frames = fw_tstamp.frames_decoded;
    361	tstamp->pcm_io_frames = div_u64(fw_tstamp.hardware_counter,
    362			(u64)stream->num_ch * SST_GET_BYTES_PER_SAMPLE(24));
    363	tstamp->sampling_rate = fw_tstamp.sampling_frequency;
    364
    365	dev_dbg(dev, "PCM  = %u\n", tstamp->pcm_io_frames);
    366	dev_dbg(dev, "Ptr Query on strid = %d  copied_total %d, decodec %d\n",
    367		str_id, tstamp->copied_total, tstamp->pcm_frames);
    368	dev_dbg(dev, "rendered %d\n", tstamp->pcm_io_frames);
    369
    370	return 0;
    371}
    372
    373static int sst_cdev_caps(struct snd_compr_caps *caps)
    374{
    375	caps->num_codecs = NUM_CODEC;
    376	caps->min_fragment_size = MIN_FRAGMENT_SIZE;  /* 50KB */
    377	caps->max_fragment_size = MAX_FRAGMENT_SIZE;  /* 1024KB */
    378	caps->min_fragments = MIN_FRAGMENT;
    379	caps->max_fragments = MAX_FRAGMENT;
    380	caps->codecs[0] = SND_AUDIOCODEC_MP3;
    381	caps->codecs[1] = SND_AUDIOCODEC_AAC;
    382	return 0;
    383}
    384
    385static const struct snd_compr_codec_caps caps_mp3 = {
    386	.num_descriptors = 1,
    387	.descriptor[0].max_ch = 2,
    388	.descriptor[0].sample_rates[0] = 48000,
    389	.descriptor[0].sample_rates[1] = 44100,
    390	.descriptor[0].sample_rates[2] = 32000,
    391	.descriptor[0].sample_rates[3] = 16000,
    392	.descriptor[0].sample_rates[4] = 8000,
    393	.descriptor[0].num_sample_rates = 5,
    394	.descriptor[0].bit_rate[0] = 320,
    395	.descriptor[0].bit_rate[1] = 192,
    396	.descriptor[0].num_bitrates = 2,
    397	.descriptor[0].profiles = 0,
    398	.descriptor[0].modes = SND_AUDIOCHANMODE_MP3_STEREO,
    399	.descriptor[0].formats = 0,
    400};
    401
    402static const struct snd_compr_codec_caps caps_aac = {
    403	.num_descriptors = 2,
    404	.descriptor[1].max_ch = 2,
    405	.descriptor[0].sample_rates[0] = 48000,
    406	.descriptor[0].sample_rates[1] = 44100,
    407	.descriptor[0].sample_rates[2] = 32000,
    408	.descriptor[0].sample_rates[3] = 16000,
    409	.descriptor[0].sample_rates[4] = 8000,
    410	.descriptor[0].num_sample_rates = 5,
    411	.descriptor[1].bit_rate[0] = 320,
    412	.descriptor[1].bit_rate[1] = 192,
    413	.descriptor[1].num_bitrates = 2,
    414	.descriptor[1].profiles = 0,
    415	.descriptor[1].modes = 0,
    416	.descriptor[1].formats =
    417			(SND_AUDIOSTREAMFORMAT_MP4ADTS |
    418				SND_AUDIOSTREAMFORMAT_RAW),
    419};
    420
    421static int sst_cdev_codec_caps(struct snd_compr_codec_caps *codec)
    422{
    423	if (codec->codec == SND_AUDIOCODEC_MP3)
    424		*codec = caps_mp3;
    425	else if (codec->codec == SND_AUDIOCODEC_AAC)
    426		*codec = caps_aac;
    427	else
    428		return -EINVAL;
    429
    430	return 0;
    431}
    432
    433void sst_cdev_fragment_elapsed(struct intel_sst_drv *ctx, int str_id)
    434{
    435	struct stream_info *stream;
    436
    437	dev_dbg(ctx->dev, "fragment elapsed from firmware for str_id %d\n",
    438			str_id);
    439	stream = &ctx->streams[str_id];
    440	if (stream->compr_cb)
    441		stream->compr_cb(stream->compr_cb_param);
    442}
    443
    444/*
    445 * sst_close_pcm_stream - Close PCM interface
    446 *
    447 * @str_id: stream id to be closed
    448 *
    449 * This function is called by MID sound card driver to close
    450 * an existing pcm interface
    451 */
    452static int sst_close_pcm_stream(struct device *dev, unsigned int str_id)
    453{
    454	struct stream_info *stream;
    455	int retval = 0;
    456	struct intel_sst_drv *ctx = dev_get_drvdata(dev);
    457
    458	stream = get_stream_info(ctx, str_id);
    459	if (!stream) {
    460		dev_err(ctx->dev, "stream info is NULL for str %d!!!\n", str_id);
    461		return -EINVAL;
    462	}
    463
    464	retval = free_stream_context(ctx, str_id);
    465	stream->pcm_substream = NULL;
    466	stream->status = STREAM_UN_INIT;
    467	stream->period_elapsed = NULL;
    468	ctx->stream_cnt--;
    469
    470	if (retval)
    471		dev_err(ctx->dev, "free stream returned err %d\n", retval);
    472
    473	dev_dbg(ctx->dev, "Exit\n");
    474	return 0;
    475}
    476
    477static inline int sst_calc_tstamp(struct intel_sst_drv *ctx,
    478		struct pcm_stream_info *info,
    479		struct snd_pcm_substream *substream,
    480		struct snd_sst_tstamp *fw_tstamp)
    481{
    482	size_t delay_bytes, delay_frames;
    483	size_t buffer_sz;
    484	u32 pointer_bytes, pointer_samples;
    485
    486	dev_dbg(ctx->dev, "mrfld ring_buffer_counter %llu in bytes\n",
    487			fw_tstamp->ring_buffer_counter);
    488	dev_dbg(ctx->dev, "mrfld hardware_counter %llu in bytes\n",
    489			 fw_tstamp->hardware_counter);
    490	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
    491		delay_bytes = (size_t) (fw_tstamp->ring_buffer_counter -
    492					fw_tstamp->hardware_counter);
    493	else
    494		delay_bytes = (size_t) (fw_tstamp->hardware_counter -
    495					fw_tstamp->ring_buffer_counter);
    496	delay_frames = bytes_to_frames(substream->runtime, delay_bytes);
    497	buffer_sz = snd_pcm_lib_buffer_bytes(substream);
    498	div_u64_rem(fw_tstamp->ring_buffer_counter, buffer_sz, &pointer_bytes);
    499	pointer_samples = bytes_to_samples(substream->runtime, pointer_bytes);
    500
    501	dev_dbg(ctx->dev, "pcm delay %zu in bytes\n", delay_bytes);
    502
    503	info->buffer_ptr = pointer_samples / substream->runtime->channels;
    504
    505	info->pcm_delay = delay_frames;
    506	dev_dbg(ctx->dev, "buffer ptr %llu pcm_delay rep: %llu\n",
    507			info->buffer_ptr, info->pcm_delay);
    508	return 0;
    509}
    510
    511static int sst_read_timestamp(struct device *dev, struct pcm_stream_info *info)
    512{
    513	struct stream_info *stream;
    514	struct snd_pcm_substream *substream;
    515	struct snd_sst_tstamp fw_tstamp;
    516	unsigned int str_id;
    517	struct intel_sst_drv *ctx = dev_get_drvdata(dev);
    518	void __iomem *addr;
    519
    520	str_id = info->str_id;
    521	stream = get_stream_info(ctx, str_id);
    522	if (!stream)
    523		return -EINVAL;
    524
    525	if (!stream->pcm_substream)
    526		return -EINVAL;
    527	substream = stream->pcm_substream;
    528
    529	addr = (void __iomem *)(ctx->mailbox + ctx->tstamp) +
    530		(str_id * sizeof(fw_tstamp));
    531
    532	memcpy_fromio(&fw_tstamp, addr, sizeof(fw_tstamp));
    533
    534	return sst_calc_tstamp(ctx, info, substream, &fw_tstamp);
    535}
    536
    537static int sst_stream_start(struct device *dev, int str_id)
    538{
    539	struct stream_info *str_info;
    540	struct intel_sst_drv *ctx = dev_get_drvdata(dev);
    541
    542	if (ctx->sst_state != SST_FW_RUNNING)
    543		return 0;
    544	str_info = get_stream_info(ctx, str_id);
    545	if (!str_info)
    546		return -EINVAL;
    547	str_info->prev = str_info->status;
    548	str_info->status = STREAM_RUNNING;
    549	sst_start_stream(ctx, str_id);
    550
    551	return 0;
    552}
    553
    554static int sst_stream_drop(struct device *dev, int str_id)
    555{
    556	struct stream_info *str_info;
    557	struct intel_sst_drv *ctx = dev_get_drvdata(dev);
    558
    559	if (ctx->sst_state != SST_FW_RUNNING)
    560		return 0;
    561
    562	str_info = get_stream_info(ctx, str_id);
    563	if (!str_info)
    564		return -EINVAL;
    565	str_info->prev = STREAM_UN_INIT;
    566	str_info->status = STREAM_INIT;
    567	return sst_drop_stream(ctx, str_id);
    568}
    569
    570static int sst_stream_pause(struct device *dev, int str_id)
    571{
    572	struct stream_info *str_info;
    573	struct intel_sst_drv *ctx = dev_get_drvdata(dev);
    574
    575	if (ctx->sst_state != SST_FW_RUNNING)
    576		return 0;
    577
    578	str_info = get_stream_info(ctx, str_id);
    579	if (!str_info)
    580		return -EINVAL;
    581
    582	return sst_pause_stream(ctx, str_id);
    583}
    584
    585static int sst_stream_resume(struct device *dev, int str_id)
    586{
    587	struct stream_info *str_info;
    588	struct intel_sst_drv *ctx = dev_get_drvdata(dev);
    589
    590	if (ctx->sst_state != SST_FW_RUNNING)
    591		return 0;
    592
    593	str_info = get_stream_info(ctx, str_id);
    594	if (!str_info)
    595		return -EINVAL;
    596	return sst_resume_stream(ctx, str_id);
    597}
    598
    599static int sst_stream_init(struct device *dev, struct pcm_stream_info *str_info)
    600{
    601	int str_id = 0;
    602	struct stream_info *stream;
    603	struct intel_sst_drv *ctx = dev_get_drvdata(dev);
    604
    605	str_id = str_info->str_id;
    606
    607	if (ctx->sst_state != SST_FW_RUNNING)
    608		return 0;
    609
    610	stream = get_stream_info(ctx, str_id);
    611	if (!stream)
    612		return -EINVAL;
    613
    614	dev_dbg(ctx->dev, "setting the period ptrs\n");
    615	stream->pcm_substream = str_info->arg;
    616	stream->period_elapsed = str_info->period_elapsed;
    617	stream->sfreq = str_info->sfreq;
    618	stream->prev = stream->status;
    619	stream->status = STREAM_INIT;
    620	dev_dbg(ctx->dev,
    621		"pcm_substream %p, period_elapsed %p, sfreq %d, status %d\n",
    622		stream->pcm_substream, stream->period_elapsed,
    623		stream->sfreq, stream->status);
    624
    625	return 0;
    626}
    627
    628/*
    629 * sst_set_byte_stream - Set generic params
    630 *
    631 * @cmd: control cmd to be set
    632 * @arg: command argument
    633 *
    634 * This function is called by MID sound card driver to configure
    635 * SST runtime params.
    636 */
    637static int sst_send_byte_stream(struct device *dev,
    638		struct snd_sst_bytes_v2 *bytes)
    639{
    640	int ret_val = 0;
    641	struct intel_sst_drv *ctx = dev_get_drvdata(dev);
    642
    643	if (NULL == bytes)
    644		return -EINVAL;
    645	ret_val = pm_runtime_resume_and_get(ctx->dev);
    646	if (ret_val < 0)
    647		return ret_val;
    648
    649	ret_val = sst_send_byte_stream_mrfld(ctx, bytes);
    650	sst_pm_runtime_put(ctx);
    651
    652	return ret_val;
    653}
    654
    655static struct sst_ops pcm_ops = {
    656	.open = sst_open_pcm_stream,
    657	.stream_init = sst_stream_init,
    658	.stream_start = sst_stream_start,
    659	.stream_drop = sst_stream_drop,
    660	.stream_pause = sst_stream_pause,
    661	.stream_pause_release = sst_stream_resume,
    662	.stream_read_tstamp = sst_read_timestamp,
    663	.send_byte_stream = sst_send_byte_stream,
    664	.close = sst_close_pcm_stream,
    665	.power = sst_power_control,
    666};
    667
    668static struct compress_sst_ops compr_ops = {
    669	.open = sst_cdev_open,
    670	.close = sst_cdev_close,
    671	.stream_pause = sst_cdev_stream_pause,
    672	.stream_pause_release = sst_cdev_stream_pause_release,
    673	.stream_start = sst_cdev_stream_start,
    674	.stream_drop = sst_cdev_stream_drop,
    675	.stream_drain = sst_cdev_stream_drain,
    676	.stream_partial_drain = sst_cdev_stream_partial_drain,
    677	.tstamp = sst_cdev_tstamp,
    678	.ack = sst_cdev_ack,
    679	.get_caps = sst_cdev_caps,
    680	.get_codec_caps = sst_cdev_codec_caps,
    681	.set_metadata = sst_cdev_set_metadata,
    682	.power = sst_power_control,
    683};
    684
    685static struct sst_device sst_dsp_device = {
    686	.name = "Intel(R) SST LPE",
    687	.dev = NULL,
    688	.ops = &pcm_ops,
    689	.compr_ops = &compr_ops,
    690};
    691
    692/*
    693 * sst_register - function to register DSP
    694 *
    695 * This functions registers DSP with the platform driver
    696 */
    697int sst_register(struct device *dev)
    698{
    699	int ret_val;
    700
    701	sst_dsp_device.dev = dev;
    702	ret_val = sst_register_dsp(&sst_dsp_device);
    703	if (ret_val)
    704		dev_err(dev, "Unable to register DSP with platform driver\n");
    705
    706	return ret_val;
    707}
    708
    709int sst_unregister(struct device *dev)
    710{
    711	return sst_unregister_dsp(&sst_dsp_device);
    712}