18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  sst_mfld_platform.c - Intel MID Platform driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (C) 2010-2014 Intel Corp
68c2ecf20Sopenharmony_ci *  Author: Vinod Koul <vinod.koul@intel.com>
78c2ecf20Sopenharmony_ci *  Author: Harsha Priya <priya.harsha@intel.com>
88c2ecf20Sopenharmony_ci *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <linux/slab.h>
158c2ecf20Sopenharmony_ci#include <linux/io.h>
168c2ecf20Sopenharmony_ci#include <linux/module.h>
178c2ecf20Sopenharmony_ci#include <sound/core.h>
188c2ecf20Sopenharmony_ci#include <sound/pcm.h>
198c2ecf20Sopenharmony_ci#include <sound/pcm_params.h>
208c2ecf20Sopenharmony_ci#include <sound/soc.h>
218c2ecf20Sopenharmony_ci#include <sound/compress_driver.h>
228c2ecf20Sopenharmony_ci#include <asm/platform_sst_audio.h>
238c2ecf20Sopenharmony_ci#include "sst-mfld-platform.h"
248c2ecf20Sopenharmony_ci#include "sst-atom-controls.h"
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistruct sst_device *sst;
278c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(sst_lock);
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ciint sst_register_dsp(struct sst_device *dev)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci	if (WARN_ON(!dev))
328c2ecf20Sopenharmony_ci		return -EINVAL;
338c2ecf20Sopenharmony_ci	if (!try_module_get(dev->dev->driver->owner))
348c2ecf20Sopenharmony_ci		return -ENODEV;
358c2ecf20Sopenharmony_ci	mutex_lock(&sst_lock);
368c2ecf20Sopenharmony_ci	if (sst) {
378c2ecf20Sopenharmony_ci		dev_err(dev->dev, "we already have a device %s\n", sst->name);
388c2ecf20Sopenharmony_ci		module_put(dev->dev->driver->owner);
398c2ecf20Sopenharmony_ci		mutex_unlock(&sst_lock);
408c2ecf20Sopenharmony_ci		return -EEXIST;
418c2ecf20Sopenharmony_ci	}
428c2ecf20Sopenharmony_ci	dev_dbg(dev->dev, "registering device %s\n", dev->name);
438c2ecf20Sopenharmony_ci	sst = dev;
448c2ecf20Sopenharmony_ci	mutex_unlock(&sst_lock);
458c2ecf20Sopenharmony_ci	return 0;
468c2ecf20Sopenharmony_ci}
478c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sst_register_dsp);
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ciint sst_unregister_dsp(struct sst_device *dev)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	if (WARN_ON(!dev))
528c2ecf20Sopenharmony_ci		return -EINVAL;
538c2ecf20Sopenharmony_ci	if (dev != sst)
548c2ecf20Sopenharmony_ci		return -EINVAL;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	mutex_lock(&sst_lock);
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	if (!sst) {
598c2ecf20Sopenharmony_ci		mutex_unlock(&sst_lock);
608c2ecf20Sopenharmony_ci		return -EIO;
618c2ecf20Sopenharmony_ci	}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	module_put(sst->dev->driver->owner);
648c2ecf20Sopenharmony_ci	dev_dbg(dev->dev, "unreg %s\n", sst->name);
658c2ecf20Sopenharmony_ci	sst = NULL;
668c2ecf20Sopenharmony_ci	mutex_unlock(&sst_lock);
678c2ecf20Sopenharmony_ci	return 0;
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sst_unregister_dsp);
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistatic const struct snd_pcm_hardware sst_platform_pcm_hw = {
728c2ecf20Sopenharmony_ci	.info =	(SNDRV_PCM_INFO_INTERLEAVED |
738c2ecf20Sopenharmony_ci			SNDRV_PCM_INFO_DOUBLE |
748c2ecf20Sopenharmony_ci			SNDRV_PCM_INFO_PAUSE |
758c2ecf20Sopenharmony_ci			SNDRV_PCM_INFO_RESUME |
768c2ecf20Sopenharmony_ci			SNDRV_PCM_INFO_MMAP|
778c2ecf20Sopenharmony_ci			SNDRV_PCM_INFO_MMAP_VALID |
788c2ecf20Sopenharmony_ci			SNDRV_PCM_INFO_BLOCK_TRANSFER |
798c2ecf20Sopenharmony_ci			SNDRV_PCM_INFO_SYNC_START),
808c2ecf20Sopenharmony_ci	.buffer_bytes_max = SST_MAX_BUFFER,
818c2ecf20Sopenharmony_ci	.period_bytes_min = SST_MIN_PERIOD_BYTES,
828c2ecf20Sopenharmony_ci	.period_bytes_max = SST_MAX_PERIOD_BYTES,
838c2ecf20Sopenharmony_ci	.periods_min = SST_MIN_PERIODS,
848c2ecf20Sopenharmony_ci	.periods_max = SST_MAX_PERIODS,
858c2ecf20Sopenharmony_ci	.fifo_size = SST_FIFO_SIZE,
868c2ecf20Sopenharmony_ci};
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistatic struct sst_dev_stream_map dpcm_strm_map[] = {
898c2ecf20Sopenharmony_ci	{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, /* Reserved, not in use */
908c2ecf20Sopenharmony_ci	{MERR_DPCM_AUDIO, 0, SNDRV_PCM_STREAM_PLAYBACK, PIPE_MEDIA1_IN, SST_TASK_ID_MEDIA, 0},
918c2ecf20Sopenharmony_ci	{MERR_DPCM_COMPR, 0, SNDRV_PCM_STREAM_PLAYBACK, PIPE_MEDIA0_IN, SST_TASK_ID_MEDIA, 0},
928c2ecf20Sopenharmony_ci	{MERR_DPCM_AUDIO, 0, SNDRV_PCM_STREAM_CAPTURE, PIPE_PCM1_OUT, SST_TASK_ID_MEDIA, 0},
938c2ecf20Sopenharmony_ci	{MERR_DPCM_DEEP_BUFFER, 0, SNDRV_PCM_STREAM_PLAYBACK, PIPE_MEDIA3_IN, SST_TASK_ID_MEDIA, 0},
948c2ecf20Sopenharmony_ci};
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic int sst_media_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	return sst_send_pipe_gains(dai, stream, mute);
1008c2ecf20Sopenharmony_ci}
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci/* helper functions */
1038c2ecf20Sopenharmony_civoid sst_set_stream_status(struct sst_runtime_stream *stream,
1048c2ecf20Sopenharmony_ci					int state)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci	unsigned long flags;
1078c2ecf20Sopenharmony_ci	spin_lock_irqsave(&stream->status_lock, flags);
1088c2ecf20Sopenharmony_ci	stream->stream_status = state;
1098c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&stream->status_lock, flags);
1108c2ecf20Sopenharmony_ci}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_cistatic inline int sst_get_stream_status(struct sst_runtime_stream *stream)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	int state;
1158c2ecf20Sopenharmony_ci	unsigned long flags;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	spin_lock_irqsave(&stream->status_lock, flags);
1188c2ecf20Sopenharmony_ci	state = stream->stream_status;
1198c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&stream->status_lock, flags);
1208c2ecf20Sopenharmony_ci	return state;
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic void sst_fill_alloc_params(struct snd_pcm_substream *substream,
1248c2ecf20Sopenharmony_ci				struct snd_sst_alloc_params_ext *alloc_param)
1258c2ecf20Sopenharmony_ci{
1268c2ecf20Sopenharmony_ci	unsigned int channels;
1278c2ecf20Sopenharmony_ci	snd_pcm_uframes_t period_size;
1288c2ecf20Sopenharmony_ci	ssize_t periodbytes;
1298c2ecf20Sopenharmony_ci	ssize_t buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
1308c2ecf20Sopenharmony_ci	u32 buffer_addr = virt_to_phys(substream->runtime->dma_area);
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	channels = substream->runtime->channels;
1338c2ecf20Sopenharmony_ci	period_size = substream->runtime->period_size;
1348c2ecf20Sopenharmony_ci	periodbytes = samples_to_bytes(substream->runtime, period_size);
1358c2ecf20Sopenharmony_ci	alloc_param->ring_buf_info[0].addr = buffer_addr;
1368c2ecf20Sopenharmony_ci	alloc_param->ring_buf_info[0].size = buffer_bytes;
1378c2ecf20Sopenharmony_ci	alloc_param->sg_count = 1;
1388c2ecf20Sopenharmony_ci	alloc_param->reserved = 0;
1398c2ecf20Sopenharmony_ci	alloc_param->frag_size = periodbytes * channels;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_cistatic void sst_fill_pcm_params(struct snd_pcm_substream *substream,
1438c2ecf20Sopenharmony_ci				struct snd_sst_stream_params *param)
1448c2ecf20Sopenharmony_ci{
1458c2ecf20Sopenharmony_ci	param->uc.pcm_params.num_chan = (u8) substream->runtime->channels;
1468c2ecf20Sopenharmony_ci	param->uc.pcm_params.pcm_wd_sz = substream->runtime->sample_bits;
1478c2ecf20Sopenharmony_ci	param->uc.pcm_params.sfreq = substream->runtime->rate;
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	/* PCM stream via ALSA interface */
1508c2ecf20Sopenharmony_ci	param->uc.pcm_params.use_offload_path = 0;
1518c2ecf20Sopenharmony_ci	param->uc.pcm_params.reserved2 = 0;
1528c2ecf20Sopenharmony_ci	memset(param->uc.pcm_params.channel_map, 0, sizeof(u8));
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_cistatic int sst_get_stream_mapping(int dev, int sdev, int dir,
1578c2ecf20Sopenharmony_ci	struct sst_dev_stream_map *map, int size)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	int i;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	if (map == NULL)
1628c2ecf20Sopenharmony_ci		return -EINVAL;
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	/* index 0 is not used in stream map */
1668c2ecf20Sopenharmony_ci	for (i = 1; i < size; i++) {
1678c2ecf20Sopenharmony_ci		if ((map[i].dev_num == dev) && (map[i].direction == dir))
1688c2ecf20Sopenharmony_ci			return i;
1698c2ecf20Sopenharmony_ci	}
1708c2ecf20Sopenharmony_ci	return 0;
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ciint sst_fill_stream_params(void *substream,
1748c2ecf20Sopenharmony_ci	const struct sst_data *ctx, struct snd_sst_params *str_params, bool is_compress)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	int map_size;
1778c2ecf20Sopenharmony_ci	int index;
1788c2ecf20Sopenharmony_ci	struct sst_dev_stream_map *map;
1798c2ecf20Sopenharmony_ci	struct snd_pcm_substream *pstream = NULL;
1808c2ecf20Sopenharmony_ci	struct snd_compr_stream *cstream = NULL;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	map = ctx->pdata->pdev_strm_map;
1838c2ecf20Sopenharmony_ci	map_size = ctx->pdata->strm_map_size;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	if (is_compress)
1868c2ecf20Sopenharmony_ci		cstream = (struct snd_compr_stream *)substream;
1878c2ecf20Sopenharmony_ci	else
1888c2ecf20Sopenharmony_ci		pstream = (struct snd_pcm_substream *)substream;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	str_params->stream_type = SST_STREAM_TYPE_MUSIC;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	/* For pcm streams */
1938c2ecf20Sopenharmony_ci	if (pstream) {
1948c2ecf20Sopenharmony_ci		index = sst_get_stream_mapping(pstream->pcm->device,
1958c2ecf20Sopenharmony_ci					  pstream->number, pstream->stream,
1968c2ecf20Sopenharmony_ci					  map, map_size);
1978c2ecf20Sopenharmony_ci		if (index <= 0)
1988c2ecf20Sopenharmony_ci			return -EINVAL;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci		str_params->stream_id = index;
2018c2ecf20Sopenharmony_ci		str_params->device_type = map[index].device_id;
2028c2ecf20Sopenharmony_ci		str_params->task = map[index].task_id;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci		str_params->ops = (u8)pstream->stream;
2058c2ecf20Sopenharmony_ci	}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	if (cstream) {
2088c2ecf20Sopenharmony_ci		index = sst_get_stream_mapping(cstream->device->device,
2098c2ecf20Sopenharmony_ci					       0, cstream->direction,
2108c2ecf20Sopenharmony_ci					       map, map_size);
2118c2ecf20Sopenharmony_ci		if (index <= 0)
2128c2ecf20Sopenharmony_ci			return -EINVAL;
2138c2ecf20Sopenharmony_ci		str_params->stream_id = index;
2148c2ecf20Sopenharmony_ci		str_params->device_type = map[index].device_id;
2158c2ecf20Sopenharmony_ci		str_params->task = map[index].task_id;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci		str_params->ops = (u8)cstream->direction;
2188c2ecf20Sopenharmony_ci	}
2198c2ecf20Sopenharmony_ci	return 0;
2208c2ecf20Sopenharmony_ci}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_cistatic int sst_platform_alloc_stream(struct snd_pcm_substream *substream,
2238c2ecf20Sopenharmony_ci		struct snd_soc_dai *dai)
2248c2ecf20Sopenharmony_ci{
2258c2ecf20Sopenharmony_ci	struct sst_runtime_stream *stream =
2268c2ecf20Sopenharmony_ci			substream->runtime->private_data;
2278c2ecf20Sopenharmony_ci	struct snd_sst_stream_params param = {{{0,},},};
2288c2ecf20Sopenharmony_ci	struct snd_sst_params str_params = {0};
2298c2ecf20Sopenharmony_ci	struct snd_sst_alloc_params_ext alloc_params = {0};
2308c2ecf20Sopenharmony_ci	int ret_val = 0;
2318c2ecf20Sopenharmony_ci	struct sst_data *ctx = snd_soc_dai_get_drvdata(dai);
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	/* set codec params and inform SST driver the same */
2348c2ecf20Sopenharmony_ci	sst_fill_pcm_params(substream, &param);
2358c2ecf20Sopenharmony_ci	sst_fill_alloc_params(substream, &alloc_params);
2368c2ecf20Sopenharmony_ci	str_params.sparams = param;
2378c2ecf20Sopenharmony_ci	str_params.aparams = alloc_params;
2388c2ecf20Sopenharmony_ci	str_params.codec = SST_CODEC_TYPE_PCM;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	/* fill the device type and stream id to pass to SST driver */
2418c2ecf20Sopenharmony_ci	ret_val = sst_fill_stream_params(substream, ctx, &str_params, false);
2428c2ecf20Sopenharmony_ci	if (ret_val < 0)
2438c2ecf20Sopenharmony_ci		return ret_val;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	stream->stream_info.str_id = str_params.stream_id;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	ret_val = stream->ops->open(sst->dev, &str_params);
2488c2ecf20Sopenharmony_ci	if (ret_val <= 0)
2498c2ecf20Sopenharmony_ci		return ret_val;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	return ret_val;
2538c2ecf20Sopenharmony_ci}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_cistatic void sst_period_elapsed(void *arg)
2568c2ecf20Sopenharmony_ci{
2578c2ecf20Sopenharmony_ci	struct snd_pcm_substream *substream = arg;
2588c2ecf20Sopenharmony_ci	struct sst_runtime_stream *stream;
2598c2ecf20Sopenharmony_ci	int status;
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	if (!substream || !substream->runtime)
2628c2ecf20Sopenharmony_ci		return;
2638c2ecf20Sopenharmony_ci	stream = substream->runtime->private_data;
2648c2ecf20Sopenharmony_ci	if (!stream)
2658c2ecf20Sopenharmony_ci		return;
2668c2ecf20Sopenharmony_ci	status = sst_get_stream_status(stream);
2678c2ecf20Sopenharmony_ci	if (status != SST_PLATFORM_RUNNING)
2688c2ecf20Sopenharmony_ci		return;
2698c2ecf20Sopenharmony_ci	snd_pcm_period_elapsed(substream);
2708c2ecf20Sopenharmony_ci}
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_cistatic int sst_platform_init_stream(struct snd_pcm_substream *substream)
2738c2ecf20Sopenharmony_ci{
2748c2ecf20Sopenharmony_ci	struct sst_runtime_stream *stream =
2758c2ecf20Sopenharmony_ci			substream->runtime->private_data;
2768c2ecf20Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
2778c2ecf20Sopenharmony_ci	int ret_val;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	dev_dbg(rtd->dev, "setting buffer ptr param\n");
2808c2ecf20Sopenharmony_ci	sst_set_stream_status(stream, SST_PLATFORM_INIT);
2818c2ecf20Sopenharmony_ci	stream->stream_info.period_elapsed = sst_period_elapsed;
2828c2ecf20Sopenharmony_ci	stream->stream_info.arg = substream;
2838c2ecf20Sopenharmony_ci	stream->stream_info.buffer_ptr = 0;
2848c2ecf20Sopenharmony_ci	stream->stream_info.sfreq = substream->runtime->rate;
2858c2ecf20Sopenharmony_ci	ret_val = stream->ops->stream_init(sst->dev, &stream->stream_info);
2868c2ecf20Sopenharmony_ci	if (ret_val)
2878c2ecf20Sopenharmony_ci		dev_err(rtd->dev, "control_set ret error %d\n", ret_val);
2888c2ecf20Sopenharmony_ci	return ret_val;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_cistatic int power_up_sst(struct sst_runtime_stream *stream)
2938c2ecf20Sopenharmony_ci{
2948c2ecf20Sopenharmony_ci	return stream->ops->power(sst->dev, true);
2958c2ecf20Sopenharmony_ci}
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_cistatic void power_down_sst(struct sst_runtime_stream *stream)
2988c2ecf20Sopenharmony_ci{
2998c2ecf20Sopenharmony_ci	stream->ops->power(sst->dev, false);
3008c2ecf20Sopenharmony_ci}
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_cistatic int sst_media_open(struct snd_pcm_substream *substream,
3038c2ecf20Sopenharmony_ci		struct snd_soc_dai *dai)
3048c2ecf20Sopenharmony_ci{
3058c2ecf20Sopenharmony_ci	int ret_val = 0;
3068c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
3078c2ecf20Sopenharmony_ci	struct sst_runtime_stream *stream;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	stream = kzalloc(sizeof(*stream), GFP_KERNEL);
3108c2ecf20Sopenharmony_ci	if (!stream)
3118c2ecf20Sopenharmony_ci		return -ENOMEM;
3128c2ecf20Sopenharmony_ci	spin_lock_init(&stream->status_lock);
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	/* get the sst ops */
3158c2ecf20Sopenharmony_ci	mutex_lock(&sst_lock);
3168c2ecf20Sopenharmony_ci	if (!sst ||
3178c2ecf20Sopenharmony_ci	    !try_module_get(sst->dev->driver->owner)) {
3188c2ecf20Sopenharmony_ci		dev_err(dai->dev, "no device available to run\n");
3198c2ecf20Sopenharmony_ci		ret_val = -ENODEV;
3208c2ecf20Sopenharmony_ci		goto out_ops;
3218c2ecf20Sopenharmony_ci	}
3228c2ecf20Sopenharmony_ci	stream->ops = sst->ops;
3238c2ecf20Sopenharmony_ci	mutex_unlock(&sst_lock);
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	stream->stream_info.str_id = 0;
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	stream->stream_info.arg = substream;
3288c2ecf20Sopenharmony_ci	/* allocate memory for SST API set */
3298c2ecf20Sopenharmony_ci	runtime->private_data = stream;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	ret_val = power_up_sst(stream);
3328c2ecf20Sopenharmony_ci	if (ret_val < 0)
3338c2ecf20Sopenharmony_ci		goto out_power_up;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	/*
3368c2ecf20Sopenharmony_ci	 * Make sure the period to be multiple of 1ms to align the
3378c2ecf20Sopenharmony_ci	 * design of firmware. Apply same rule to buffer size to make
3388c2ecf20Sopenharmony_ci	 * sure alsa could always find a value for period size
3398c2ecf20Sopenharmony_ci	 * regardless the buffer size given by user space.
3408c2ecf20Sopenharmony_ci	 */
3418c2ecf20Sopenharmony_ci	snd_pcm_hw_constraint_step(substream->runtime, 0,
3428c2ecf20Sopenharmony_ci			   SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 48);
3438c2ecf20Sopenharmony_ci	snd_pcm_hw_constraint_step(substream->runtime, 0,
3448c2ecf20Sopenharmony_ci			   SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 48);
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	/* Make sure, that the period size is always even */
3478c2ecf20Sopenharmony_ci	snd_pcm_hw_constraint_step(substream->runtime, 0,
3488c2ecf20Sopenharmony_ci			   SNDRV_PCM_HW_PARAM_PERIODS, 2);
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	return snd_pcm_hw_constraint_integer(runtime,
3518c2ecf20Sopenharmony_ci			 SNDRV_PCM_HW_PARAM_PERIODS);
3528c2ecf20Sopenharmony_ciout_ops:
3538c2ecf20Sopenharmony_ci	mutex_unlock(&sst_lock);
3548c2ecf20Sopenharmony_ciout_power_up:
3558c2ecf20Sopenharmony_ci	kfree(stream);
3568c2ecf20Sopenharmony_ci	return ret_val;
3578c2ecf20Sopenharmony_ci}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_cistatic void sst_media_close(struct snd_pcm_substream *substream,
3608c2ecf20Sopenharmony_ci		struct snd_soc_dai *dai)
3618c2ecf20Sopenharmony_ci{
3628c2ecf20Sopenharmony_ci	struct sst_runtime_stream *stream;
3638c2ecf20Sopenharmony_ci	int str_id;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	stream = substream->runtime->private_data;
3668c2ecf20Sopenharmony_ci	power_down_sst(stream);
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	str_id = stream->stream_info.str_id;
3698c2ecf20Sopenharmony_ci	if (str_id)
3708c2ecf20Sopenharmony_ci		stream->ops->close(sst->dev, str_id);
3718c2ecf20Sopenharmony_ci	module_put(sst->dev->driver->owner);
3728c2ecf20Sopenharmony_ci	kfree(stream);
3738c2ecf20Sopenharmony_ci}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_cistatic int sst_media_prepare(struct snd_pcm_substream *substream,
3768c2ecf20Sopenharmony_ci		struct snd_soc_dai *dai)
3778c2ecf20Sopenharmony_ci{
3788c2ecf20Sopenharmony_ci	struct sst_runtime_stream *stream;
3798c2ecf20Sopenharmony_ci	int ret_val, str_id;
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	stream = substream->runtime->private_data;
3828c2ecf20Sopenharmony_ci	str_id = stream->stream_info.str_id;
3838c2ecf20Sopenharmony_ci	if (stream->stream_info.str_id) {
3848c2ecf20Sopenharmony_ci		ret_val = stream->ops->stream_drop(sst->dev, str_id);
3858c2ecf20Sopenharmony_ci		return ret_val;
3868c2ecf20Sopenharmony_ci	}
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	ret_val = sst_platform_alloc_stream(substream, dai);
3898c2ecf20Sopenharmony_ci	if (ret_val <= 0)
3908c2ecf20Sopenharmony_ci		return ret_val;
3918c2ecf20Sopenharmony_ci	snprintf(substream->pcm->id, sizeof(substream->pcm->id),
3928c2ecf20Sopenharmony_ci			"%d", stream->stream_info.str_id);
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	ret_val = sst_platform_init_stream(substream);
3958c2ecf20Sopenharmony_ci	if (ret_val)
3968c2ecf20Sopenharmony_ci		return ret_val;
3978c2ecf20Sopenharmony_ci	substream->runtime->hw.info = SNDRV_PCM_INFO_BLOCK_TRANSFER;
3988c2ecf20Sopenharmony_ci	return 0;
3998c2ecf20Sopenharmony_ci}
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_cistatic int sst_enable_ssp(struct snd_pcm_substream *substream,
4028c2ecf20Sopenharmony_ci			struct snd_soc_dai *dai)
4038c2ecf20Sopenharmony_ci{
4048c2ecf20Sopenharmony_ci	int ret = 0;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	if (!snd_soc_dai_active(dai)) {
4078c2ecf20Sopenharmony_ci		ret = sst_handle_vb_timer(dai, true);
4088c2ecf20Sopenharmony_ci		sst_fill_ssp_defaults(dai);
4098c2ecf20Sopenharmony_ci	}
4108c2ecf20Sopenharmony_ci	return ret;
4118c2ecf20Sopenharmony_ci}
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_cistatic int sst_be_hw_params(struct snd_pcm_substream *substream,
4148c2ecf20Sopenharmony_ci				struct snd_pcm_hw_params *params,
4158c2ecf20Sopenharmony_ci				struct snd_soc_dai *dai)
4168c2ecf20Sopenharmony_ci{
4178c2ecf20Sopenharmony_ci	int ret = 0;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	if (snd_soc_dai_active(dai) == 1)
4208c2ecf20Sopenharmony_ci		ret = send_ssp_cmd(dai, dai->name, 1);
4218c2ecf20Sopenharmony_ci	return ret;
4228c2ecf20Sopenharmony_ci}
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_cistatic int sst_set_format(struct snd_soc_dai *dai, unsigned int fmt)
4258c2ecf20Sopenharmony_ci{
4268c2ecf20Sopenharmony_ci	int ret = 0;
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	if (!snd_soc_dai_active(dai))
4298c2ecf20Sopenharmony_ci		return 0;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	ret = sst_fill_ssp_config(dai, fmt);
4328c2ecf20Sopenharmony_ci	if (ret < 0)
4338c2ecf20Sopenharmony_ci		dev_err(dai->dev, "sst_set_format failed..\n");
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	return ret;
4368c2ecf20Sopenharmony_ci}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_cistatic int sst_platform_set_ssp_slot(struct snd_soc_dai *dai,
4398c2ecf20Sopenharmony_ci			unsigned int tx_mask, unsigned int rx_mask,
4408c2ecf20Sopenharmony_ci			int slots, int slot_width) {
4418c2ecf20Sopenharmony_ci	int ret = 0;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	if (!snd_soc_dai_active(dai))
4448c2ecf20Sopenharmony_ci		return ret;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	ret = sst_fill_ssp_slot(dai, tx_mask, rx_mask, slots, slot_width);
4478c2ecf20Sopenharmony_ci	if (ret < 0)
4488c2ecf20Sopenharmony_ci		dev_err(dai->dev, "sst_fill_ssp_slot failed..%d\n", ret);
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	return ret;
4518c2ecf20Sopenharmony_ci}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_cistatic void sst_disable_ssp(struct snd_pcm_substream *substream,
4548c2ecf20Sopenharmony_ci			struct snd_soc_dai *dai)
4558c2ecf20Sopenharmony_ci{
4568c2ecf20Sopenharmony_ci	if (!snd_soc_dai_active(dai)) {
4578c2ecf20Sopenharmony_ci		send_ssp_cmd(dai, dai->name, 0);
4588c2ecf20Sopenharmony_ci		sst_handle_vb_timer(dai, false);
4598c2ecf20Sopenharmony_ci	}
4608c2ecf20Sopenharmony_ci}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops sst_media_dai_ops = {
4638c2ecf20Sopenharmony_ci	.startup = sst_media_open,
4648c2ecf20Sopenharmony_ci	.shutdown = sst_media_close,
4658c2ecf20Sopenharmony_ci	.prepare = sst_media_prepare,
4668c2ecf20Sopenharmony_ci	.mute_stream = sst_media_digital_mute,
4678c2ecf20Sopenharmony_ci};
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops sst_compr_dai_ops = {
4708c2ecf20Sopenharmony_ci	.mute_stream = sst_media_digital_mute,
4718c2ecf20Sopenharmony_ci};
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops sst_be_dai_ops = {
4748c2ecf20Sopenharmony_ci	.startup = sst_enable_ssp,
4758c2ecf20Sopenharmony_ci	.hw_params = sst_be_hw_params,
4768c2ecf20Sopenharmony_ci	.set_fmt = sst_set_format,
4778c2ecf20Sopenharmony_ci	.set_tdm_slot = sst_platform_set_ssp_slot,
4788c2ecf20Sopenharmony_ci	.shutdown = sst_disable_ssp,
4798c2ecf20Sopenharmony_ci};
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver sst_platform_dai[] = {
4828c2ecf20Sopenharmony_ci{
4838c2ecf20Sopenharmony_ci	.name = "media-cpu-dai",
4848c2ecf20Sopenharmony_ci	.ops = &sst_media_dai_ops,
4858c2ecf20Sopenharmony_ci	.playback = {
4868c2ecf20Sopenharmony_ci		.stream_name = "Headset Playback",
4878c2ecf20Sopenharmony_ci		.channels_min = SST_STEREO,
4888c2ecf20Sopenharmony_ci		.channels_max = SST_STEREO,
4898c2ecf20Sopenharmony_ci		.rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000,
4908c2ecf20Sopenharmony_ci		.formats = SNDRV_PCM_FMTBIT_S16_LE,
4918c2ecf20Sopenharmony_ci	},
4928c2ecf20Sopenharmony_ci	.capture = {
4938c2ecf20Sopenharmony_ci		.stream_name = "Headset Capture",
4948c2ecf20Sopenharmony_ci		.channels_min = 1,
4958c2ecf20Sopenharmony_ci		.channels_max = 2,
4968c2ecf20Sopenharmony_ci		.rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000,
4978c2ecf20Sopenharmony_ci		.formats = SNDRV_PCM_FMTBIT_S16_LE,
4988c2ecf20Sopenharmony_ci	},
4998c2ecf20Sopenharmony_ci},
5008c2ecf20Sopenharmony_ci{
5018c2ecf20Sopenharmony_ci	.name = "deepbuffer-cpu-dai",
5028c2ecf20Sopenharmony_ci	.ops = &sst_media_dai_ops,
5038c2ecf20Sopenharmony_ci	.playback = {
5048c2ecf20Sopenharmony_ci		.stream_name = "Deepbuffer Playback",
5058c2ecf20Sopenharmony_ci		.channels_min = SST_STEREO,
5068c2ecf20Sopenharmony_ci		.channels_max = SST_STEREO,
5078c2ecf20Sopenharmony_ci		.rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000,
5088c2ecf20Sopenharmony_ci		.formats = SNDRV_PCM_FMTBIT_S16_LE,
5098c2ecf20Sopenharmony_ci	},
5108c2ecf20Sopenharmony_ci},
5118c2ecf20Sopenharmony_ci{
5128c2ecf20Sopenharmony_ci	.name = "compress-cpu-dai",
5138c2ecf20Sopenharmony_ci	.compress_new = snd_soc_new_compress,
5148c2ecf20Sopenharmony_ci	.ops = &sst_compr_dai_ops,
5158c2ecf20Sopenharmony_ci	.playback = {
5168c2ecf20Sopenharmony_ci		.stream_name = "Compress Playback",
5178c2ecf20Sopenharmony_ci		.channels_min = 1,
5188c2ecf20Sopenharmony_ci	},
5198c2ecf20Sopenharmony_ci},
5208c2ecf20Sopenharmony_ci/* BE CPU  Dais */
5218c2ecf20Sopenharmony_ci{
5228c2ecf20Sopenharmony_ci	.name = "ssp0-port",
5238c2ecf20Sopenharmony_ci	.ops = &sst_be_dai_ops,
5248c2ecf20Sopenharmony_ci	.playback = {
5258c2ecf20Sopenharmony_ci		.stream_name = "ssp0 Tx",
5268c2ecf20Sopenharmony_ci		.channels_min = SST_STEREO,
5278c2ecf20Sopenharmony_ci		.channels_max = SST_STEREO,
5288c2ecf20Sopenharmony_ci		.rates = SNDRV_PCM_RATE_48000,
5298c2ecf20Sopenharmony_ci		.formats = SNDRV_PCM_FMTBIT_S16_LE,
5308c2ecf20Sopenharmony_ci	},
5318c2ecf20Sopenharmony_ci	.capture = {
5328c2ecf20Sopenharmony_ci		.stream_name = "ssp0 Rx",
5338c2ecf20Sopenharmony_ci		.channels_min = SST_STEREO,
5348c2ecf20Sopenharmony_ci		.channels_max = SST_STEREO,
5358c2ecf20Sopenharmony_ci		.rates = SNDRV_PCM_RATE_48000,
5368c2ecf20Sopenharmony_ci		.formats = SNDRV_PCM_FMTBIT_S16_LE,
5378c2ecf20Sopenharmony_ci	},
5388c2ecf20Sopenharmony_ci},
5398c2ecf20Sopenharmony_ci{
5408c2ecf20Sopenharmony_ci	.name = "ssp1-port",
5418c2ecf20Sopenharmony_ci	.ops = &sst_be_dai_ops,
5428c2ecf20Sopenharmony_ci	.playback = {
5438c2ecf20Sopenharmony_ci		.stream_name = "ssp1 Tx",
5448c2ecf20Sopenharmony_ci		.channels_min = SST_STEREO,
5458c2ecf20Sopenharmony_ci		.channels_max = SST_STEREO,
5468c2ecf20Sopenharmony_ci		.rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000,
5478c2ecf20Sopenharmony_ci		.formats = SNDRV_PCM_FMTBIT_S16_LE,
5488c2ecf20Sopenharmony_ci	},
5498c2ecf20Sopenharmony_ci	.capture = {
5508c2ecf20Sopenharmony_ci		.stream_name = "ssp1 Rx",
5518c2ecf20Sopenharmony_ci		.channels_min = SST_STEREO,
5528c2ecf20Sopenharmony_ci		.channels_max = SST_STEREO,
5538c2ecf20Sopenharmony_ci		.rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000,
5548c2ecf20Sopenharmony_ci		.formats = SNDRV_PCM_FMTBIT_S16_LE,
5558c2ecf20Sopenharmony_ci	},
5568c2ecf20Sopenharmony_ci},
5578c2ecf20Sopenharmony_ci{
5588c2ecf20Sopenharmony_ci	.name = "ssp2-port",
5598c2ecf20Sopenharmony_ci	.ops = &sst_be_dai_ops,
5608c2ecf20Sopenharmony_ci	.playback = {
5618c2ecf20Sopenharmony_ci		.stream_name = "ssp2 Tx",
5628c2ecf20Sopenharmony_ci		.channels_min = SST_STEREO,
5638c2ecf20Sopenharmony_ci		.channels_max = SST_STEREO,
5648c2ecf20Sopenharmony_ci		.rates = SNDRV_PCM_RATE_48000,
5658c2ecf20Sopenharmony_ci		.formats = SNDRV_PCM_FMTBIT_S16_LE,
5668c2ecf20Sopenharmony_ci	},
5678c2ecf20Sopenharmony_ci	.capture = {
5688c2ecf20Sopenharmony_ci		.stream_name = "ssp2 Rx",
5698c2ecf20Sopenharmony_ci		.channels_min = SST_STEREO,
5708c2ecf20Sopenharmony_ci		.channels_max = SST_STEREO,
5718c2ecf20Sopenharmony_ci		.rates = SNDRV_PCM_RATE_48000,
5728c2ecf20Sopenharmony_ci		.formats = SNDRV_PCM_FMTBIT_S16_LE,
5738c2ecf20Sopenharmony_ci	},
5748c2ecf20Sopenharmony_ci},
5758c2ecf20Sopenharmony_ci};
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_cistatic int sst_soc_open(struct snd_soc_component *component,
5788c2ecf20Sopenharmony_ci			struct snd_pcm_substream *substream)
5798c2ecf20Sopenharmony_ci{
5808c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime;
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	if (substream->pcm->internal)
5838c2ecf20Sopenharmony_ci		return 0;
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	runtime = substream->runtime;
5868c2ecf20Sopenharmony_ci	runtime->hw = sst_platform_pcm_hw;
5878c2ecf20Sopenharmony_ci	return 0;
5888c2ecf20Sopenharmony_ci}
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_cistatic int sst_soc_trigger(struct snd_soc_component *component,
5918c2ecf20Sopenharmony_ci			   struct snd_pcm_substream *substream, int cmd)
5928c2ecf20Sopenharmony_ci{
5938c2ecf20Sopenharmony_ci	int ret_val = 0, str_id;
5948c2ecf20Sopenharmony_ci	struct sst_runtime_stream *stream;
5958c2ecf20Sopenharmony_ci	int status;
5968c2ecf20Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	dev_dbg(rtd->dev, "%s called\n", __func__);
5998c2ecf20Sopenharmony_ci	if (substream->pcm->internal)
6008c2ecf20Sopenharmony_ci		return 0;
6018c2ecf20Sopenharmony_ci	stream = substream->runtime->private_data;
6028c2ecf20Sopenharmony_ci	str_id = stream->stream_info.str_id;
6038c2ecf20Sopenharmony_ci	switch (cmd) {
6048c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_START:
6058c2ecf20Sopenharmony_ci		dev_dbg(rtd->dev, "sst: Trigger Start\n");
6068c2ecf20Sopenharmony_ci		status = SST_PLATFORM_RUNNING;
6078c2ecf20Sopenharmony_ci		stream->stream_info.arg = substream;
6088c2ecf20Sopenharmony_ci		ret_val = stream->ops->stream_start(sst->dev, str_id);
6098c2ecf20Sopenharmony_ci		break;
6108c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_STOP:
6118c2ecf20Sopenharmony_ci		dev_dbg(rtd->dev, "sst: in stop\n");
6128c2ecf20Sopenharmony_ci		status = SST_PLATFORM_DROPPED;
6138c2ecf20Sopenharmony_ci		ret_val = stream->ops->stream_drop(sst->dev, str_id);
6148c2ecf20Sopenharmony_ci		break;
6158c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
6168c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_SUSPEND:
6178c2ecf20Sopenharmony_ci		dev_dbg(rtd->dev, "sst: in pause\n");
6188c2ecf20Sopenharmony_ci		status = SST_PLATFORM_PAUSED;
6198c2ecf20Sopenharmony_ci		ret_val = stream->ops->stream_pause(sst->dev, str_id);
6208c2ecf20Sopenharmony_ci		break;
6218c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
6228c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_RESUME:
6238c2ecf20Sopenharmony_ci		dev_dbg(rtd->dev, "sst: in pause release\n");
6248c2ecf20Sopenharmony_ci		status = SST_PLATFORM_RUNNING;
6258c2ecf20Sopenharmony_ci		ret_val = stream->ops->stream_pause_release(sst->dev, str_id);
6268c2ecf20Sopenharmony_ci		break;
6278c2ecf20Sopenharmony_ci	default:
6288c2ecf20Sopenharmony_ci		return -EINVAL;
6298c2ecf20Sopenharmony_ci	}
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	if (!ret_val)
6328c2ecf20Sopenharmony_ci		sst_set_stream_status(stream, status);
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	return ret_val;
6358c2ecf20Sopenharmony_ci}
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_cistatic snd_pcm_uframes_t sst_soc_pointer(struct snd_soc_component *component,
6398c2ecf20Sopenharmony_ci					 struct snd_pcm_substream *substream)
6408c2ecf20Sopenharmony_ci{
6418c2ecf20Sopenharmony_ci	struct sst_runtime_stream *stream;
6428c2ecf20Sopenharmony_ci	int ret_val, status;
6438c2ecf20Sopenharmony_ci	struct pcm_stream_info *str_info;
6448c2ecf20Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci	stream = substream->runtime->private_data;
6478c2ecf20Sopenharmony_ci	status = sst_get_stream_status(stream);
6488c2ecf20Sopenharmony_ci	if (status == SST_PLATFORM_INIT)
6498c2ecf20Sopenharmony_ci		return 0;
6508c2ecf20Sopenharmony_ci	str_info = &stream->stream_info;
6518c2ecf20Sopenharmony_ci	ret_val = stream->ops->stream_read_tstamp(sst->dev, str_info);
6528c2ecf20Sopenharmony_ci	if (ret_val) {
6538c2ecf20Sopenharmony_ci		dev_err(rtd->dev, "sst: error code = %d\n", ret_val);
6548c2ecf20Sopenharmony_ci		return ret_val;
6558c2ecf20Sopenharmony_ci	}
6568c2ecf20Sopenharmony_ci	substream->runtime->delay = str_info->pcm_delay;
6578c2ecf20Sopenharmony_ci	return str_info->buffer_ptr;
6588c2ecf20Sopenharmony_ci}
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_cistatic int sst_soc_pcm_new(struct snd_soc_component *component,
6618c2ecf20Sopenharmony_ci			   struct snd_soc_pcm_runtime *rtd)
6628c2ecf20Sopenharmony_ci{
6638c2ecf20Sopenharmony_ci	struct snd_soc_dai *dai = asoc_rtd_to_cpu(rtd, 0);
6648c2ecf20Sopenharmony_ci	struct snd_pcm *pcm = rtd->pcm;
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci	if (dai->driver->playback.channels_min ||
6678c2ecf20Sopenharmony_ci			dai->driver->capture.channels_min) {
6688c2ecf20Sopenharmony_ci		snd_pcm_set_managed_buffer_all(pcm,
6698c2ecf20Sopenharmony_ci			SNDRV_DMA_TYPE_CONTINUOUS,
6708c2ecf20Sopenharmony_ci			snd_dma_continuous_data(GFP_DMA),
6718c2ecf20Sopenharmony_ci			SST_MIN_BUFFER, SST_MAX_BUFFER);
6728c2ecf20Sopenharmony_ci	}
6738c2ecf20Sopenharmony_ci	return 0;
6748c2ecf20Sopenharmony_ci}
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_cistatic int sst_soc_probe(struct snd_soc_component *component)
6778c2ecf20Sopenharmony_ci{
6788c2ecf20Sopenharmony_ci	struct sst_data *drv = dev_get_drvdata(component->dev);
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci	drv->soc_card = component->card;
6818c2ecf20Sopenharmony_ci	return sst_dsp_init_v2_dpcm(component);
6828c2ecf20Sopenharmony_ci}
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_cistatic void sst_soc_remove(struct snd_soc_component *component)
6858c2ecf20Sopenharmony_ci{
6868c2ecf20Sopenharmony_ci	struct sst_data *drv = dev_get_drvdata(component->dev);
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	drv->soc_card = NULL;
6898c2ecf20Sopenharmony_ci}
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver sst_soc_platform_drv  = {
6928c2ecf20Sopenharmony_ci	.name		= DRV_NAME,
6938c2ecf20Sopenharmony_ci	.probe		= sst_soc_probe,
6948c2ecf20Sopenharmony_ci	.remove		= sst_soc_remove,
6958c2ecf20Sopenharmony_ci	.open		= sst_soc_open,
6968c2ecf20Sopenharmony_ci	.trigger	= sst_soc_trigger,
6978c2ecf20Sopenharmony_ci	.pointer	= sst_soc_pointer,
6988c2ecf20Sopenharmony_ci	.compress_ops	= &sst_platform_compress_ops,
6998c2ecf20Sopenharmony_ci	.pcm_construct	= sst_soc_pcm_new,
7008c2ecf20Sopenharmony_ci};
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_cistatic int sst_platform_probe(struct platform_device *pdev)
7038c2ecf20Sopenharmony_ci{
7048c2ecf20Sopenharmony_ci	struct sst_data *drv;
7058c2ecf20Sopenharmony_ci	int ret;
7068c2ecf20Sopenharmony_ci	struct sst_platform_data *pdata;
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
7098c2ecf20Sopenharmony_ci	if (drv == NULL) {
7108c2ecf20Sopenharmony_ci		return -ENOMEM;
7118c2ecf20Sopenharmony_ci	}
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
7148c2ecf20Sopenharmony_ci	if (pdata == NULL) {
7158c2ecf20Sopenharmony_ci		return -ENOMEM;
7168c2ecf20Sopenharmony_ci	}
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	pdata->pdev_strm_map = dpcm_strm_map;
7198c2ecf20Sopenharmony_ci	pdata->strm_map_size = ARRAY_SIZE(dpcm_strm_map);
7208c2ecf20Sopenharmony_ci	drv->pdata = pdata;
7218c2ecf20Sopenharmony_ci	drv->pdev = pdev;
7228c2ecf20Sopenharmony_ci	mutex_init(&drv->lock);
7238c2ecf20Sopenharmony_ci	dev_set_drvdata(&pdev->dev, drv);
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	ret = devm_snd_soc_register_component(&pdev->dev, &sst_soc_platform_drv,
7268c2ecf20Sopenharmony_ci				sst_platform_dai, ARRAY_SIZE(sst_platform_dai));
7278c2ecf20Sopenharmony_ci	if (ret)
7288c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "registering cpu dais failed\n");
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci	return ret;
7318c2ecf20Sopenharmony_ci}
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_cistatic int sst_platform_remove(struct platform_device *pdev)
7348c2ecf20Sopenharmony_ci{
7358c2ecf20Sopenharmony_ci	dev_dbg(&pdev->dev, "sst_platform_remove success\n");
7368c2ecf20Sopenharmony_ci	return 0;
7378c2ecf20Sopenharmony_ci}
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_cistatic int sst_soc_prepare(struct device *dev)
7428c2ecf20Sopenharmony_ci{
7438c2ecf20Sopenharmony_ci	struct sst_data *drv = dev_get_drvdata(dev);
7448c2ecf20Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd;
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	if (!drv->soc_card)
7478c2ecf20Sopenharmony_ci		return 0;
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	/* suspend all pcms first */
7508c2ecf20Sopenharmony_ci	snd_soc_suspend(drv->soc_card->dev);
7518c2ecf20Sopenharmony_ci	snd_soc_poweroff(drv->soc_card->dev);
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	/* set the SSPs to idle */
7548c2ecf20Sopenharmony_ci	for_each_card_rtds(drv->soc_card, rtd) {
7558c2ecf20Sopenharmony_ci		struct snd_soc_dai *dai = asoc_rtd_to_cpu(rtd, 0);
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci		if (snd_soc_dai_active(dai)) {
7588c2ecf20Sopenharmony_ci			send_ssp_cmd(dai, dai->name, 0);
7598c2ecf20Sopenharmony_ci			sst_handle_vb_timer(dai, false);
7608c2ecf20Sopenharmony_ci		}
7618c2ecf20Sopenharmony_ci	}
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci	return 0;
7648c2ecf20Sopenharmony_ci}
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_cistatic void sst_soc_complete(struct device *dev)
7678c2ecf20Sopenharmony_ci{
7688c2ecf20Sopenharmony_ci	struct sst_data *drv = dev_get_drvdata(dev);
7698c2ecf20Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd;
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci	if (!drv->soc_card)
7728c2ecf20Sopenharmony_ci		return;
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci	/* restart SSPs */
7758c2ecf20Sopenharmony_ci	for_each_card_rtds(drv->soc_card, rtd) {
7768c2ecf20Sopenharmony_ci		struct snd_soc_dai *dai = asoc_rtd_to_cpu(rtd, 0);
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci		if (snd_soc_dai_active(dai)) {
7798c2ecf20Sopenharmony_ci			sst_handle_vb_timer(dai, true);
7808c2ecf20Sopenharmony_ci			send_ssp_cmd(dai, dai->name, 1);
7818c2ecf20Sopenharmony_ci		}
7828c2ecf20Sopenharmony_ci	}
7838c2ecf20Sopenharmony_ci	snd_soc_resume(drv->soc_card->dev);
7848c2ecf20Sopenharmony_ci}
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci#else
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci#define sst_soc_prepare NULL
7898c2ecf20Sopenharmony_ci#define sst_soc_complete NULL
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci#endif
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_cistatic const struct dev_pm_ops sst_platform_pm = {
7958c2ecf20Sopenharmony_ci	.prepare	= sst_soc_prepare,
7968c2ecf20Sopenharmony_ci	.complete	= sst_soc_complete,
7978c2ecf20Sopenharmony_ci};
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_cistatic struct platform_driver sst_platform_driver = {
8008c2ecf20Sopenharmony_ci	.driver		= {
8018c2ecf20Sopenharmony_ci		.name		= "sst-mfld-platform",
8028c2ecf20Sopenharmony_ci		.pm             = &sst_platform_pm,
8038c2ecf20Sopenharmony_ci	},
8048c2ecf20Sopenharmony_ci	.probe		= sst_platform_probe,
8058c2ecf20Sopenharmony_ci	.remove		= sst_platform_remove,
8068c2ecf20Sopenharmony_ci};
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_cimodule_platform_driver(sst_platform_driver);
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ASoC Intel(R) MID Platform driver");
8118c2ecf20Sopenharmony_ciMODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
8128c2ecf20Sopenharmony_ciMODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
8138c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
8148c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:sst-atom-hifi2-platform");
8158c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:sst-mfld-platform");
816