18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci// Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
38c2ecf20Sopenharmony_ci// Copyright (c) 2018, Linaro Limited
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci#include <linux/init.h>
68c2ecf20Sopenharmony_ci#include <linux/err.h>
78c2ecf20Sopenharmony_ci#include <linux/module.h>
88c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
98c2ecf20Sopenharmony_ci#include <linux/slab.h>
108c2ecf20Sopenharmony_ci#include <sound/soc.h>
118c2ecf20Sopenharmony_ci#include <sound/soc-dapm.h>
128c2ecf20Sopenharmony_ci#include <sound/pcm.h>
138c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
148c2ecf20Sopenharmony_ci#include <sound/compress_driver.h>
158c2ecf20Sopenharmony_ci#include <asm/dma.h>
168c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
178c2ecf20Sopenharmony_ci#include <linux/of_device.h>
188c2ecf20Sopenharmony_ci#include <sound/pcm_params.h>
198c2ecf20Sopenharmony_ci#include "q6asm.h"
208c2ecf20Sopenharmony_ci#include "q6routing.h"
218c2ecf20Sopenharmony_ci#include "q6dsp-errno.h"
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define DRV_NAME	"q6asm-fe-dai"
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#define PLAYBACK_MIN_NUM_PERIODS    2
268c2ecf20Sopenharmony_ci#define PLAYBACK_MAX_NUM_PERIODS   8
278c2ecf20Sopenharmony_ci#define PLAYBACK_MAX_PERIOD_SIZE    65536
288c2ecf20Sopenharmony_ci#define PLAYBACK_MIN_PERIOD_SIZE    128
298c2ecf20Sopenharmony_ci#define CAPTURE_MIN_NUM_PERIODS     2
308c2ecf20Sopenharmony_ci#define CAPTURE_MAX_NUM_PERIODS     8
318c2ecf20Sopenharmony_ci#define CAPTURE_MAX_PERIOD_SIZE     4096
328c2ecf20Sopenharmony_ci#define CAPTURE_MIN_PERIOD_SIZE     320
338c2ecf20Sopenharmony_ci#define SID_MASK_DEFAULT	0xF
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci/* Default values used if user space does not set */
368c2ecf20Sopenharmony_ci#define COMPR_PLAYBACK_MIN_FRAGMENT_SIZE (8 * 1024)
378c2ecf20Sopenharmony_ci#define COMPR_PLAYBACK_MAX_FRAGMENT_SIZE (128 * 1024)
388c2ecf20Sopenharmony_ci#define COMPR_PLAYBACK_MIN_NUM_FRAGMENTS (4)
398c2ecf20Sopenharmony_ci#define COMPR_PLAYBACK_MAX_NUM_FRAGMENTS (16 * 4)
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci#define ALAC_CH_LAYOUT_MONO   ((101 << 16) | 1)
428c2ecf20Sopenharmony_ci#define ALAC_CH_LAYOUT_STEREO ((101 << 16) | 2)
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cienum stream_state {
458c2ecf20Sopenharmony_ci	Q6ASM_STREAM_IDLE = 0,
468c2ecf20Sopenharmony_ci	Q6ASM_STREAM_STOPPED,
478c2ecf20Sopenharmony_ci	Q6ASM_STREAM_RUNNING,
488c2ecf20Sopenharmony_ci};
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistruct q6asm_dai_rtd {
518c2ecf20Sopenharmony_ci	struct snd_pcm_substream *substream;
528c2ecf20Sopenharmony_ci	struct snd_compr_stream *cstream;
538c2ecf20Sopenharmony_ci	struct snd_codec codec;
548c2ecf20Sopenharmony_ci	struct snd_dma_buffer dma_buffer;
558c2ecf20Sopenharmony_ci	spinlock_t lock;
568c2ecf20Sopenharmony_ci	phys_addr_t phys;
578c2ecf20Sopenharmony_ci	unsigned int pcm_size;
588c2ecf20Sopenharmony_ci	unsigned int pcm_count;
598c2ecf20Sopenharmony_ci	unsigned int pcm_irq_pos;       /* IRQ position */
608c2ecf20Sopenharmony_ci	unsigned int periods;
618c2ecf20Sopenharmony_ci	unsigned int bytes_sent;
628c2ecf20Sopenharmony_ci	unsigned int bytes_received;
638c2ecf20Sopenharmony_ci	unsigned int copied_total;
648c2ecf20Sopenharmony_ci	uint16_t bits_per_sample;
658c2ecf20Sopenharmony_ci	uint16_t source; /* Encoding source bit mask */
668c2ecf20Sopenharmony_ci	struct audio_client *audio_client;
678c2ecf20Sopenharmony_ci	uint32_t next_track_stream_id;
688c2ecf20Sopenharmony_ci	bool next_track;
698c2ecf20Sopenharmony_ci	uint32_t stream_id;
708c2ecf20Sopenharmony_ci	uint16_t session_id;
718c2ecf20Sopenharmony_ci	enum stream_state state;
728c2ecf20Sopenharmony_ci	uint32_t initial_samples_drop;
738c2ecf20Sopenharmony_ci	uint32_t trailing_samples_drop;
748c2ecf20Sopenharmony_ci	bool notify_on_drain;
758c2ecf20Sopenharmony_ci};
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_cistruct q6asm_dai_data {
788c2ecf20Sopenharmony_ci	struct snd_soc_dai_driver *dais;
798c2ecf20Sopenharmony_ci	int num_dais;
808c2ecf20Sopenharmony_ci	long long int sid;
818c2ecf20Sopenharmony_ci};
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_cistatic const struct snd_pcm_hardware q6asm_dai_hardware_capture = {
848c2ecf20Sopenharmony_ci	.info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BATCH |
858c2ecf20Sopenharmony_ci				SNDRV_PCM_INFO_BLOCK_TRANSFER |
868c2ecf20Sopenharmony_ci				SNDRV_PCM_INFO_MMAP_VALID |
878c2ecf20Sopenharmony_ci				SNDRV_PCM_INFO_INTERLEAVED |
888c2ecf20Sopenharmony_ci				SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
898c2ecf20Sopenharmony_ci	.formats =              (SNDRV_PCM_FMTBIT_S16_LE |
908c2ecf20Sopenharmony_ci				SNDRV_PCM_FMTBIT_S24_LE),
918c2ecf20Sopenharmony_ci	.rates =                SNDRV_PCM_RATE_8000_48000,
928c2ecf20Sopenharmony_ci	.rate_min =             8000,
938c2ecf20Sopenharmony_ci	.rate_max =             48000,
948c2ecf20Sopenharmony_ci	.channels_min =         1,
958c2ecf20Sopenharmony_ci	.channels_max =         4,
968c2ecf20Sopenharmony_ci	.buffer_bytes_max =     CAPTURE_MAX_NUM_PERIODS *
978c2ecf20Sopenharmony_ci				CAPTURE_MAX_PERIOD_SIZE,
988c2ecf20Sopenharmony_ci	.period_bytes_min =	CAPTURE_MIN_PERIOD_SIZE,
998c2ecf20Sopenharmony_ci	.period_bytes_max =     CAPTURE_MAX_PERIOD_SIZE,
1008c2ecf20Sopenharmony_ci	.periods_min =          CAPTURE_MIN_NUM_PERIODS,
1018c2ecf20Sopenharmony_ci	.periods_max =          CAPTURE_MAX_NUM_PERIODS,
1028c2ecf20Sopenharmony_ci	.fifo_size =            0,
1038c2ecf20Sopenharmony_ci};
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_cistatic struct snd_pcm_hardware q6asm_dai_hardware_playback = {
1068c2ecf20Sopenharmony_ci	.info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BATCH |
1078c2ecf20Sopenharmony_ci				SNDRV_PCM_INFO_BLOCK_TRANSFER |
1088c2ecf20Sopenharmony_ci				SNDRV_PCM_INFO_MMAP_VALID |
1098c2ecf20Sopenharmony_ci				SNDRV_PCM_INFO_INTERLEAVED |
1108c2ecf20Sopenharmony_ci				SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
1118c2ecf20Sopenharmony_ci	.formats =              (SNDRV_PCM_FMTBIT_S16_LE |
1128c2ecf20Sopenharmony_ci				SNDRV_PCM_FMTBIT_S24_LE),
1138c2ecf20Sopenharmony_ci	.rates =                SNDRV_PCM_RATE_8000_192000,
1148c2ecf20Sopenharmony_ci	.rate_min =             8000,
1158c2ecf20Sopenharmony_ci	.rate_max =             192000,
1168c2ecf20Sopenharmony_ci	.channels_min =         1,
1178c2ecf20Sopenharmony_ci	.channels_max =         8,
1188c2ecf20Sopenharmony_ci	.buffer_bytes_max =     (PLAYBACK_MAX_NUM_PERIODS *
1198c2ecf20Sopenharmony_ci				PLAYBACK_MAX_PERIOD_SIZE),
1208c2ecf20Sopenharmony_ci	.period_bytes_min =	PLAYBACK_MIN_PERIOD_SIZE,
1218c2ecf20Sopenharmony_ci	.period_bytes_max =     PLAYBACK_MAX_PERIOD_SIZE,
1228c2ecf20Sopenharmony_ci	.periods_min =          PLAYBACK_MIN_NUM_PERIODS,
1238c2ecf20Sopenharmony_ci	.periods_max =          PLAYBACK_MAX_NUM_PERIODS,
1248c2ecf20Sopenharmony_ci	.fifo_size =            0,
1258c2ecf20Sopenharmony_ci};
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci#define Q6ASM_FEDAI_DRIVER(num) { \
1288c2ecf20Sopenharmony_ci		.playback = {						\
1298c2ecf20Sopenharmony_ci			.stream_name = "MultiMedia"#num" Playback",	\
1308c2ecf20Sopenharmony_ci			.rates = (SNDRV_PCM_RATE_8000_192000|		\
1318c2ecf20Sopenharmony_ci					SNDRV_PCM_RATE_KNOT),		\
1328c2ecf20Sopenharmony_ci			.formats = (SNDRV_PCM_FMTBIT_S16_LE |		\
1338c2ecf20Sopenharmony_ci					SNDRV_PCM_FMTBIT_S24_LE),	\
1348c2ecf20Sopenharmony_ci			.channels_min = 1,				\
1358c2ecf20Sopenharmony_ci			.channels_max = 8,				\
1368c2ecf20Sopenharmony_ci			.rate_min =     8000,				\
1378c2ecf20Sopenharmony_ci			.rate_max =	192000,				\
1388c2ecf20Sopenharmony_ci		},							\
1398c2ecf20Sopenharmony_ci		.capture = {						\
1408c2ecf20Sopenharmony_ci			.stream_name = "MultiMedia"#num" Capture",	\
1418c2ecf20Sopenharmony_ci			.rates = (SNDRV_PCM_RATE_8000_48000|		\
1428c2ecf20Sopenharmony_ci					SNDRV_PCM_RATE_KNOT),		\
1438c2ecf20Sopenharmony_ci			.formats = (SNDRV_PCM_FMTBIT_S16_LE |		\
1448c2ecf20Sopenharmony_ci				    SNDRV_PCM_FMTBIT_S24_LE),		\
1458c2ecf20Sopenharmony_ci			.channels_min = 1,				\
1468c2ecf20Sopenharmony_ci			.channels_max = 4,				\
1478c2ecf20Sopenharmony_ci			.rate_min =     8000,				\
1488c2ecf20Sopenharmony_ci			.rate_max =	48000,				\
1498c2ecf20Sopenharmony_ci		},							\
1508c2ecf20Sopenharmony_ci		.name = "MultiMedia"#num,				\
1518c2ecf20Sopenharmony_ci		.id = MSM_FRONTEND_DAI_MULTIMEDIA##num,			\
1528c2ecf20Sopenharmony_ci	}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci/* Conventional and unconventional sample rate supported */
1558c2ecf20Sopenharmony_cistatic unsigned int supported_sample_rates[] = {
1568c2ecf20Sopenharmony_ci	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
1578c2ecf20Sopenharmony_ci	88200, 96000, 176400, 192000
1588c2ecf20Sopenharmony_ci};
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_cistatic struct snd_pcm_hw_constraint_list constraints_sample_rates = {
1618c2ecf20Sopenharmony_ci	.count = ARRAY_SIZE(supported_sample_rates),
1628c2ecf20Sopenharmony_ci	.list = supported_sample_rates,
1638c2ecf20Sopenharmony_ci	.mask = 0,
1648c2ecf20Sopenharmony_ci};
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_cistatic const struct snd_compr_codec_caps q6asm_compr_caps = {
1678c2ecf20Sopenharmony_ci	.num_descriptors = 1,
1688c2ecf20Sopenharmony_ci	.descriptor[0].max_ch = 2,
1698c2ecf20Sopenharmony_ci	.descriptor[0].sample_rates = {	8000, 11025, 12000, 16000, 22050,
1708c2ecf20Sopenharmony_ci					24000, 32000, 44100, 48000, 88200,
1718c2ecf20Sopenharmony_ci					96000, 176400, 192000 },
1728c2ecf20Sopenharmony_ci	.descriptor[0].num_sample_rates = 13,
1738c2ecf20Sopenharmony_ci	.descriptor[0].bit_rate[0] = 320,
1748c2ecf20Sopenharmony_ci	.descriptor[0].bit_rate[1] = 128,
1758c2ecf20Sopenharmony_ci	.descriptor[0].num_bitrates = 2,
1768c2ecf20Sopenharmony_ci	.descriptor[0].profiles = 0,
1778c2ecf20Sopenharmony_ci	.descriptor[0].modes = SND_AUDIOCHANMODE_MP3_STEREO,
1788c2ecf20Sopenharmony_ci	.descriptor[0].formats = 0,
1798c2ecf20Sopenharmony_ci};
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_cistatic void event_handler(uint32_t opcode, uint32_t token,
1828c2ecf20Sopenharmony_ci			  void *payload, void *priv)
1838c2ecf20Sopenharmony_ci{
1848c2ecf20Sopenharmony_ci	struct q6asm_dai_rtd *prtd = priv;
1858c2ecf20Sopenharmony_ci	struct snd_pcm_substream *substream = prtd->substream;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	switch (opcode) {
1888c2ecf20Sopenharmony_ci	case ASM_CLIENT_EVENT_CMD_RUN_DONE:
1898c2ecf20Sopenharmony_ci		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1908c2ecf20Sopenharmony_ci			q6asm_write_async(prtd->audio_client, prtd->stream_id,
1918c2ecf20Sopenharmony_ci				   prtd->pcm_count, 0, 0, 0);
1928c2ecf20Sopenharmony_ci		break;
1938c2ecf20Sopenharmony_ci	case ASM_CLIENT_EVENT_CMD_EOS_DONE:
1948c2ecf20Sopenharmony_ci		prtd->state = Q6ASM_STREAM_STOPPED;
1958c2ecf20Sopenharmony_ci		break;
1968c2ecf20Sopenharmony_ci	case ASM_CLIENT_EVENT_DATA_WRITE_DONE: {
1978c2ecf20Sopenharmony_ci		prtd->pcm_irq_pos += prtd->pcm_count;
1988c2ecf20Sopenharmony_ci		snd_pcm_period_elapsed(substream);
1998c2ecf20Sopenharmony_ci		if (prtd->state == Q6ASM_STREAM_RUNNING)
2008c2ecf20Sopenharmony_ci			q6asm_write_async(prtd->audio_client, prtd->stream_id,
2018c2ecf20Sopenharmony_ci					   prtd->pcm_count, 0, 0, 0);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci		break;
2048c2ecf20Sopenharmony_ci		}
2058c2ecf20Sopenharmony_ci	case ASM_CLIENT_EVENT_DATA_READ_DONE:
2068c2ecf20Sopenharmony_ci		prtd->pcm_irq_pos += prtd->pcm_count;
2078c2ecf20Sopenharmony_ci		snd_pcm_period_elapsed(substream);
2088c2ecf20Sopenharmony_ci		if (prtd->state == Q6ASM_STREAM_RUNNING)
2098c2ecf20Sopenharmony_ci			q6asm_read(prtd->audio_client, prtd->stream_id);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci		break;
2128c2ecf20Sopenharmony_ci	default:
2138c2ecf20Sopenharmony_ci		break;
2148c2ecf20Sopenharmony_ci	}
2158c2ecf20Sopenharmony_ci}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_cistatic int q6asm_dai_prepare(struct snd_soc_component *component,
2188c2ecf20Sopenharmony_ci			     struct snd_pcm_substream *substream)
2198c2ecf20Sopenharmony_ci{
2208c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
2218c2ecf20Sopenharmony_ci	struct snd_soc_pcm_runtime *soc_prtd = asoc_substream_to_rtd(substream);
2228c2ecf20Sopenharmony_ci	struct q6asm_dai_rtd *prtd = runtime->private_data;
2238c2ecf20Sopenharmony_ci	struct q6asm_dai_data *pdata;
2248c2ecf20Sopenharmony_ci	struct device *dev = component->dev;
2258c2ecf20Sopenharmony_ci	int ret, i;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	pdata = snd_soc_component_get_drvdata(component);
2288c2ecf20Sopenharmony_ci	if (!pdata)
2298c2ecf20Sopenharmony_ci		return -EINVAL;
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	if (!prtd || !prtd->audio_client) {
2328c2ecf20Sopenharmony_ci		dev_err(dev, "%s: private data null or audio client freed\n",
2338c2ecf20Sopenharmony_ci			__func__);
2348c2ecf20Sopenharmony_ci		return -EINVAL;
2358c2ecf20Sopenharmony_ci	}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
2388c2ecf20Sopenharmony_ci	prtd->pcm_irq_pos = 0;
2398c2ecf20Sopenharmony_ci	/* rate and channels are sent to audio driver */
2408c2ecf20Sopenharmony_ci	if (prtd->state) {
2418c2ecf20Sopenharmony_ci		/* clear the previous setup if any  */
2428c2ecf20Sopenharmony_ci		q6asm_cmd(prtd->audio_client, prtd->stream_id, CMD_CLOSE);
2438c2ecf20Sopenharmony_ci		q6asm_unmap_memory_regions(substream->stream,
2448c2ecf20Sopenharmony_ci					   prtd->audio_client);
2458c2ecf20Sopenharmony_ci		q6routing_stream_close(soc_prtd->dai_link->id,
2468c2ecf20Sopenharmony_ci					 substream->stream);
2478c2ecf20Sopenharmony_ci	}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	ret = q6asm_map_memory_regions(substream->stream, prtd->audio_client,
2508c2ecf20Sopenharmony_ci				       prtd->phys,
2518c2ecf20Sopenharmony_ci				       (prtd->pcm_size / prtd->periods),
2528c2ecf20Sopenharmony_ci				       prtd->periods);
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	if (ret < 0) {
2558c2ecf20Sopenharmony_ci		dev_err(dev, "Audio Start: Buffer Allocation failed rc = %d\n",
2568c2ecf20Sopenharmony_ci							ret);
2578c2ecf20Sopenharmony_ci		return -ENOMEM;
2588c2ecf20Sopenharmony_ci	}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
2618c2ecf20Sopenharmony_ci		ret = q6asm_open_write(prtd->audio_client, prtd->stream_id,
2628c2ecf20Sopenharmony_ci				       FORMAT_LINEAR_PCM,
2638c2ecf20Sopenharmony_ci				       0, prtd->bits_per_sample, false);
2648c2ecf20Sopenharmony_ci	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
2658c2ecf20Sopenharmony_ci		ret = q6asm_open_read(prtd->audio_client, prtd->stream_id,
2668c2ecf20Sopenharmony_ci				      FORMAT_LINEAR_PCM,
2678c2ecf20Sopenharmony_ci				      prtd->bits_per_sample);
2688c2ecf20Sopenharmony_ci	}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	if (ret < 0) {
2718c2ecf20Sopenharmony_ci		dev_err(dev, "%s: q6asm_open_write failed\n", __func__);
2728c2ecf20Sopenharmony_ci		goto open_err;
2738c2ecf20Sopenharmony_ci	}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	prtd->session_id = q6asm_get_session_id(prtd->audio_client);
2768c2ecf20Sopenharmony_ci	ret = q6routing_stream_open(soc_prtd->dai_link->id, LEGACY_PCM_MODE,
2778c2ecf20Sopenharmony_ci			      prtd->session_id, substream->stream);
2788c2ecf20Sopenharmony_ci	if (ret) {
2798c2ecf20Sopenharmony_ci		dev_err(dev, "%s: stream reg failed ret:%d\n", __func__, ret);
2808c2ecf20Sopenharmony_ci		goto routing_err;
2818c2ecf20Sopenharmony_ci	}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
2848c2ecf20Sopenharmony_ci		ret = q6asm_media_format_block_multi_ch_pcm(
2858c2ecf20Sopenharmony_ci				prtd->audio_client, prtd->stream_id,
2868c2ecf20Sopenharmony_ci				runtime->rate, runtime->channels, NULL,
2878c2ecf20Sopenharmony_ci				prtd->bits_per_sample);
2888c2ecf20Sopenharmony_ci	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
2898c2ecf20Sopenharmony_ci		ret = q6asm_enc_cfg_blk_pcm_format_support(prtd->audio_client,
2908c2ecf20Sopenharmony_ci							   prtd->stream_id,
2918c2ecf20Sopenharmony_ci							   runtime->rate,
2928c2ecf20Sopenharmony_ci							   runtime->channels,
2938c2ecf20Sopenharmony_ci							   prtd->bits_per_sample);
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci		/* Queue the buffers */
2968c2ecf20Sopenharmony_ci		for (i = 0; i < runtime->periods; i++)
2978c2ecf20Sopenharmony_ci			q6asm_read(prtd->audio_client, prtd->stream_id);
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	}
3008c2ecf20Sopenharmony_ci	if (ret < 0)
3018c2ecf20Sopenharmony_ci		dev_info(dev, "%s: CMD Format block failed\n", __func__);
3028c2ecf20Sopenharmony_ci	else
3038c2ecf20Sopenharmony_ci		prtd->state = Q6ASM_STREAM_RUNNING;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	return ret;
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_cirouting_err:
3088c2ecf20Sopenharmony_ci	q6asm_cmd(prtd->audio_client, prtd->stream_id,  CMD_CLOSE);
3098c2ecf20Sopenharmony_ciopen_err:
3108c2ecf20Sopenharmony_ci	q6asm_unmap_memory_regions(substream->stream, prtd->audio_client);
3118c2ecf20Sopenharmony_ci	q6asm_audio_client_free(prtd->audio_client);
3128c2ecf20Sopenharmony_ci	prtd->audio_client = NULL;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	return ret;
3158c2ecf20Sopenharmony_ci}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_cistatic int q6asm_dai_trigger(struct snd_soc_component *component,
3188c2ecf20Sopenharmony_ci			     struct snd_pcm_substream *substream, int cmd)
3198c2ecf20Sopenharmony_ci{
3208c2ecf20Sopenharmony_ci	int ret = 0;
3218c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
3228c2ecf20Sopenharmony_ci	struct q6asm_dai_rtd *prtd = runtime->private_data;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	switch (cmd) {
3258c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_START:
3268c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_RESUME:
3278c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
3288c2ecf20Sopenharmony_ci		ret = q6asm_run_nowait(prtd->audio_client, prtd->stream_id,
3298c2ecf20Sopenharmony_ci				       0, 0, 0);
3308c2ecf20Sopenharmony_ci		break;
3318c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_STOP:
3328c2ecf20Sopenharmony_ci		prtd->state = Q6ASM_STREAM_STOPPED;
3338c2ecf20Sopenharmony_ci		ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id,
3348c2ecf20Sopenharmony_ci				       CMD_EOS);
3358c2ecf20Sopenharmony_ci		break;
3368c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_SUSPEND:
3378c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
3388c2ecf20Sopenharmony_ci		ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id,
3398c2ecf20Sopenharmony_ci				       CMD_PAUSE);
3408c2ecf20Sopenharmony_ci		break;
3418c2ecf20Sopenharmony_ci	default:
3428c2ecf20Sopenharmony_ci		ret = -EINVAL;
3438c2ecf20Sopenharmony_ci		break;
3448c2ecf20Sopenharmony_ci	}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	return ret;
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_cistatic int q6asm_dai_open(struct snd_soc_component *component,
3508c2ecf20Sopenharmony_ci			  struct snd_pcm_substream *substream)
3518c2ecf20Sopenharmony_ci{
3528c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
3538c2ecf20Sopenharmony_ci	struct snd_soc_pcm_runtime *soc_prtd = asoc_substream_to_rtd(substream);
3548c2ecf20Sopenharmony_ci	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_prtd, 0);
3558c2ecf20Sopenharmony_ci	struct q6asm_dai_rtd *prtd;
3568c2ecf20Sopenharmony_ci	struct q6asm_dai_data *pdata;
3578c2ecf20Sopenharmony_ci	struct device *dev = component->dev;
3588c2ecf20Sopenharmony_ci	int ret = 0;
3598c2ecf20Sopenharmony_ci	int stream_id;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	stream_id = cpu_dai->driver->id;
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	pdata = snd_soc_component_get_drvdata(component);
3648c2ecf20Sopenharmony_ci	if (!pdata) {
3658c2ecf20Sopenharmony_ci		dev_err(dev, "Drv data not found ..\n");
3668c2ecf20Sopenharmony_ci		return -EINVAL;
3678c2ecf20Sopenharmony_ci	}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	prtd = kzalloc(sizeof(struct q6asm_dai_rtd), GFP_KERNEL);
3708c2ecf20Sopenharmony_ci	if (prtd == NULL)
3718c2ecf20Sopenharmony_ci		return -ENOMEM;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	prtd->substream = substream;
3748c2ecf20Sopenharmony_ci	prtd->audio_client = q6asm_audio_client_alloc(dev,
3758c2ecf20Sopenharmony_ci				(q6asm_cb)event_handler, prtd, stream_id,
3768c2ecf20Sopenharmony_ci				LEGACY_PCM_MODE);
3778c2ecf20Sopenharmony_ci	if (IS_ERR(prtd->audio_client)) {
3788c2ecf20Sopenharmony_ci		dev_info(dev, "%s: Could not allocate memory\n", __func__);
3798c2ecf20Sopenharmony_ci		ret = PTR_ERR(prtd->audio_client);
3808c2ecf20Sopenharmony_ci		kfree(prtd);
3818c2ecf20Sopenharmony_ci		return ret;
3828c2ecf20Sopenharmony_ci	}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	/* DSP expects stream id from 1 */
3858c2ecf20Sopenharmony_ci	prtd->stream_id = 1;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
3888c2ecf20Sopenharmony_ci		runtime->hw = q6asm_dai_hardware_playback;
3898c2ecf20Sopenharmony_ci	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
3908c2ecf20Sopenharmony_ci		runtime->hw = q6asm_dai_hardware_capture;
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	ret = snd_pcm_hw_constraint_list(runtime, 0,
3938c2ecf20Sopenharmony_ci				SNDRV_PCM_HW_PARAM_RATE,
3948c2ecf20Sopenharmony_ci				&constraints_sample_rates);
3958c2ecf20Sopenharmony_ci	if (ret < 0)
3968c2ecf20Sopenharmony_ci		dev_info(dev, "snd_pcm_hw_constraint_list failed\n");
3978c2ecf20Sopenharmony_ci	/* Ensure that buffer size is a multiple of period size */
3988c2ecf20Sopenharmony_ci	ret = snd_pcm_hw_constraint_integer(runtime,
3998c2ecf20Sopenharmony_ci					    SNDRV_PCM_HW_PARAM_PERIODS);
4008c2ecf20Sopenharmony_ci	if (ret < 0)
4018c2ecf20Sopenharmony_ci		dev_info(dev, "snd_pcm_hw_constraint_integer failed\n");
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
4048c2ecf20Sopenharmony_ci		ret = snd_pcm_hw_constraint_minmax(runtime,
4058c2ecf20Sopenharmony_ci			SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
4068c2ecf20Sopenharmony_ci			PLAYBACK_MIN_NUM_PERIODS * PLAYBACK_MIN_PERIOD_SIZE,
4078c2ecf20Sopenharmony_ci			PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE);
4088c2ecf20Sopenharmony_ci		if (ret < 0) {
4098c2ecf20Sopenharmony_ci			dev_err(dev, "constraint for buffer bytes min max ret = %d\n",
4108c2ecf20Sopenharmony_ci				ret);
4118c2ecf20Sopenharmony_ci		}
4128c2ecf20Sopenharmony_ci	}
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	ret = snd_pcm_hw_constraint_step(runtime, 0,
4158c2ecf20Sopenharmony_ci		SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
4168c2ecf20Sopenharmony_ci	if (ret < 0) {
4178c2ecf20Sopenharmony_ci		dev_err(dev, "constraint for period bytes step ret = %d\n",
4188c2ecf20Sopenharmony_ci								ret);
4198c2ecf20Sopenharmony_ci	}
4208c2ecf20Sopenharmony_ci	ret = snd_pcm_hw_constraint_step(runtime, 0,
4218c2ecf20Sopenharmony_ci		SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
4228c2ecf20Sopenharmony_ci	if (ret < 0) {
4238c2ecf20Sopenharmony_ci		dev_err(dev, "constraint for buffer bytes step ret = %d\n",
4248c2ecf20Sopenharmony_ci								ret);
4258c2ecf20Sopenharmony_ci	}
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	runtime->private_data = prtd;
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	snd_soc_set_runtime_hwparams(substream, &q6asm_dai_hardware_playback);
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	runtime->dma_bytes = q6asm_dai_hardware_playback.buffer_bytes_max;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	if (pdata->sid < 0)
4358c2ecf20Sopenharmony_ci		prtd->phys = substream->dma_buffer.addr;
4368c2ecf20Sopenharmony_ci	else
4378c2ecf20Sopenharmony_ci		prtd->phys = substream->dma_buffer.addr | (pdata->sid << 32);
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	return 0;
4428c2ecf20Sopenharmony_ci}
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_cistatic int q6asm_dai_close(struct snd_soc_component *component,
4458c2ecf20Sopenharmony_ci			   struct snd_pcm_substream *substream)
4468c2ecf20Sopenharmony_ci{
4478c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
4488c2ecf20Sopenharmony_ci	struct snd_soc_pcm_runtime *soc_prtd = asoc_substream_to_rtd(substream);
4498c2ecf20Sopenharmony_ci	struct q6asm_dai_rtd *prtd = runtime->private_data;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	if (prtd->audio_client) {
4528c2ecf20Sopenharmony_ci		if (prtd->state)
4538c2ecf20Sopenharmony_ci			q6asm_cmd(prtd->audio_client, prtd->stream_id,
4548c2ecf20Sopenharmony_ci				  CMD_CLOSE);
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci		q6asm_unmap_memory_regions(substream->stream,
4578c2ecf20Sopenharmony_ci					   prtd->audio_client);
4588c2ecf20Sopenharmony_ci		q6asm_audio_client_free(prtd->audio_client);
4598c2ecf20Sopenharmony_ci		prtd->audio_client = NULL;
4608c2ecf20Sopenharmony_ci	}
4618c2ecf20Sopenharmony_ci	q6routing_stream_close(soc_prtd->dai_link->id,
4628c2ecf20Sopenharmony_ci						substream->stream);
4638c2ecf20Sopenharmony_ci	kfree(prtd);
4648c2ecf20Sopenharmony_ci	return 0;
4658c2ecf20Sopenharmony_ci}
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_cistatic snd_pcm_uframes_t q6asm_dai_pointer(struct snd_soc_component *component,
4688c2ecf20Sopenharmony_ci					   struct snd_pcm_substream *substream)
4698c2ecf20Sopenharmony_ci{
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
4728c2ecf20Sopenharmony_ci	struct q6asm_dai_rtd *prtd = runtime->private_data;
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	if (prtd->pcm_irq_pos >= prtd->pcm_size)
4758c2ecf20Sopenharmony_ci		prtd->pcm_irq_pos = 0;
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
4788c2ecf20Sopenharmony_ci}
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_cistatic int q6asm_dai_mmap(struct snd_soc_component *component,
4818c2ecf20Sopenharmony_ci			  struct snd_pcm_substream *substream,
4828c2ecf20Sopenharmony_ci			  struct vm_area_struct *vma)
4838c2ecf20Sopenharmony_ci{
4848c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
4858c2ecf20Sopenharmony_ci	struct device *dev = component->dev;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	return dma_mmap_coherent(dev, vma,
4888c2ecf20Sopenharmony_ci			runtime->dma_area, runtime->dma_addr,
4898c2ecf20Sopenharmony_ci			runtime->dma_bytes);
4908c2ecf20Sopenharmony_ci}
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_cistatic int q6asm_dai_hw_params(struct snd_soc_component *component,
4938c2ecf20Sopenharmony_ci			       struct snd_pcm_substream *substream,
4948c2ecf20Sopenharmony_ci			       struct snd_pcm_hw_params *params)
4958c2ecf20Sopenharmony_ci{
4968c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
4978c2ecf20Sopenharmony_ci	struct q6asm_dai_rtd *prtd = runtime->private_data;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	prtd->pcm_size = params_buffer_bytes(params);
5008c2ecf20Sopenharmony_ci	prtd->periods = params_periods(params);
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	switch (params_format(params)) {
5038c2ecf20Sopenharmony_ci	case SNDRV_PCM_FORMAT_S16_LE:
5048c2ecf20Sopenharmony_ci		prtd->bits_per_sample = 16;
5058c2ecf20Sopenharmony_ci		break;
5068c2ecf20Sopenharmony_ci	case SNDRV_PCM_FORMAT_S24_LE:
5078c2ecf20Sopenharmony_ci		prtd->bits_per_sample = 24;
5088c2ecf20Sopenharmony_ci		break;
5098c2ecf20Sopenharmony_ci	}
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	return 0;
5128c2ecf20Sopenharmony_ci}
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_cistatic void compress_event_handler(uint32_t opcode, uint32_t token,
5158c2ecf20Sopenharmony_ci				   void *payload, void *priv)
5168c2ecf20Sopenharmony_ci{
5178c2ecf20Sopenharmony_ci	struct q6asm_dai_rtd *prtd = priv;
5188c2ecf20Sopenharmony_ci	struct snd_compr_stream *substream = prtd->cstream;
5198c2ecf20Sopenharmony_ci	unsigned long flags;
5208c2ecf20Sopenharmony_ci	u32 wflags = 0;
5218c2ecf20Sopenharmony_ci	uint64_t avail;
5228c2ecf20Sopenharmony_ci	uint32_t bytes_written, bytes_to_write;
5238c2ecf20Sopenharmony_ci	bool is_last_buffer = false;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	switch (opcode) {
5268c2ecf20Sopenharmony_ci	case ASM_CLIENT_EVENT_CMD_RUN_DONE:
5278c2ecf20Sopenharmony_ci		spin_lock_irqsave(&prtd->lock, flags);
5288c2ecf20Sopenharmony_ci		if (!prtd->bytes_sent) {
5298c2ecf20Sopenharmony_ci			q6asm_stream_remove_initial_silence(prtd->audio_client,
5308c2ecf20Sopenharmony_ci						    prtd->stream_id,
5318c2ecf20Sopenharmony_ci						    prtd->initial_samples_drop);
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci			q6asm_write_async(prtd->audio_client, prtd->stream_id,
5348c2ecf20Sopenharmony_ci					  prtd->pcm_count, 0, 0, 0);
5358c2ecf20Sopenharmony_ci			prtd->bytes_sent += prtd->pcm_count;
5368c2ecf20Sopenharmony_ci		}
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&prtd->lock, flags);
5398c2ecf20Sopenharmony_ci		break;
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	case ASM_CLIENT_EVENT_CMD_EOS_DONE:
5428c2ecf20Sopenharmony_ci		spin_lock_irqsave(&prtd->lock, flags);
5438c2ecf20Sopenharmony_ci		if (prtd->notify_on_drain) {
5448c2ecf20Sopenharmony_ci			if (substream->partial_drain) {
5458c2ecf20Sopenharmony_ci				/*
5468c2ecf20Sopenharmony_ci				 * Close old stream and make it stale, switch
5478c2ecf20Sopenharmony_ci				 * the active stream now!
5488c2ecf20Sopenharmony_ci				 */
5498c2ecf20Sopenharmony_ci				q6asm_cmd_nowait(prtd->audio_client,
5508c2ecf20Sopenharmony_ci						 prtd->stream_id,
5518c2ecf20Sopenharmony_ci						 CMD_CLOSE);
5528c2ecf20Sopenharmony_ci				/*
5538c2ecf20Sopenharmony_ci				 * vaild stream ids start from 1, So we are
5548c2ecf20Sopenharmony_ci				 * toggling this between 1 and 2.
5558c2ecf20Sopenharmony_ci				 */
5568c2ecf20Sopenharmony_ci				prtd->stream_id = (prtd->stream_id == 1 ? 2 : 1);
5578c2ecf20Sopenharmony_ci			}
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci			snd_compr_drain_notify(prtd->cstream);
5608c2ecf20Sopenharmony_ci			prtd->notify_on_drain = false;
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci		} else {
5638c2ecf20Sopenharmony_ci			prtd->state = Q6ASM_STREAM_STOPPED;
5648c2ecf20Sopenharmony_ci		}
5658c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&prtd->lock, flags);
5668c2ecf20Sopenharmony_ci		break;
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci	case ASM_CLIENT_EVENT_DATA_WRITE_DONE:
5698c2ecf20Sopenharmony_ci		spin_lock_irqsave(&prtd->lock, flags);
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci		bytes_written = token >> ASM_WRITE_TOKEN_LEN_SHIFT;
5728c2ecf20Sopenharmony_ci		prtd->copied_total += bytes_written;
5738c2ecf20Sopenharmony_ci		snd_compr_fragment_elapsed(substream);
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci		if (prtd->state != Q6ASM_STREAM_RUNNING) {
5768c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&prtd->lock, flags);
5778c2ecf20Sopenharmony_ci			break;
5788c2ecf20Sopenharmony_ci		}
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci		avail = prtd->bytes_received - prtd->bytes_sent;
5818c2ecf20Sopenharmony_ci		if (avail > prtd->pcm_count) {
5828c2ecf20Sopenharmony_ci			bytes_to_write = prtd->pcm_count;
5838c2ecf20Sopenharmony_ci		} else {
5848c2ecf20Sopenharmony_ci			if (substream->partial_drain || prtd->notify_on_drain)
5858c2ecf20Sopenharmony_ci				is_last_buffer = true;
5868c2ecf20Sopenharmony_ci			bytes_to_write = avail;
5878c2ecf20Sopenharmony_ci		}
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci		if (bytes_to_write) {
5908c2ecf20Sopenharmony_ci			if (substream->partial_drain && is_last_buffer) {
5918c2ecf20Sopenharmony_ci				wflags |= ASM_LAST_BUFFER_FLAG;
5928c2ecf20Sopenharmony_ci				q6asm_stream_remove_trailing_silence(prtd->audio_client,
5938c2ecf20Sopenharmony_ci						     prtd->stream_id,
5948c2ecf20Sopenharmony_ci						     prtd->trailing_samples_drop);
5958c2ecf20Sopenharmony_ci			}
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci			q6asm_write_async(prtd->audio_client, prtd->stream_id,
5988c2ecf20Sopenharmony_ci					  bytes_to_write, 0, 0, wflags);
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci			prtd->bytes_sent += bytes_to_write;
6018c2ecf20Sopenharmony_ci		}
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci		if (prtd->notify_on_drain && is_last_buffer)
6048c2ecf20Sopenharmony_ci			q6asm_cmd_nowait(prtd->audio_client,
6058c2ecf20Sopenharmony_ci					 prtd->stream_id, CMD_EOS);
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&prtd->lock, flags);
6088c2ecf20Sopenharmony_ci		break;
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	default:
6118c2ecf20Sopenharmony_ci		break;
6128c2ecf20Sopenharmony_ci	}
6138c2ecf20Sopenharmony_ci}
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_cistatic int q6asm_dai_compr_open(struct snd_soc_component *component,
6168c2ecf20Sopenharmony_ci				struct snd_compr_stream *stream)
6178c2ecf20Sopenharmony_ci{
6188c2ecf20Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = stream->private_data;
6198c2ecf20Sopenharmony_ci	struct snd_compr_runtime *runtime = stream->runtime;
6208c2ecf20Sopenharmony_ci	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
6218c2ecf20Sopenharmony_ci	struct q6asm_dai_data *pdata;
6228c2ecf20Sopenharmony_ci	struct device *dev = component->dev;
6238c2ecf20Sopenharmony_ci	struct q6asm_dai_rtd *prtd;
6248c2ecf20Sopenharmony_ci	int stream_id, size, ret;
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	stream_id = cpu_dai->driver->id;
6278c2ecf20Sopenharmony_ci	pdata = snd_soc_component_get_drvdata(component);
6288c2ecf20Sopenharmony_ci	if (!pdata) {
6298c2ecf20Sopenharmony_ci		dev_err(dev, "Drv data not found ..\n");
6308c2ecf20Sopenharmony_ci		return -EINVAL;
6318c2ecf20Sopenharmony_ci	}
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
6348c2ecf20Sopenharmony_ci	if (!prtd)
6358c2ecf20Sopenharmony_ci		return -ENOMEM;
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	/* DSP expects stream id from 1 */
6388c2ecf20Sopenharmony_ci	prtd->stream_id = 1;
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci	prtd->cstream = stream;
6418c2ecf20Sopenharmony_ci	prtd->audio_client = q6asm_audio_client_alloc(dev,
6428c2ecf20Sopenharmony_ci					(q6asm_cb)compress_event_handler,
6438c2ecf20Sopenharmony_ci					prtd, stream_id, LEGACY_PCM_MODE);
6448c2ecf20Sopenharmony_ci	if (IS_ERR(prtd->audio_client)) {
6458c2ecf20Sopenharmony_ci		dev_err(dev, "Could not allocate memory\n");
6468c2ecf20Sopenharmony_ci		ret = PTR_ERR(prtd->audio_client);
6478c2ecf20Sopenharmony_ci		goto free_prtd;
6488c2ecf20Sopenharmony_ci	}
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	size = COMPR_PLAYBACK_MAX_FRAGMENT_SIZE *
6518c2ecf20Sopenharmony_ci			COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
6528c2ecf20Sopenharmony_ci	ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dev, size,
6538c2ecf20Sopenharmony_ci				  &prtd->dma_buffer);
6548c2ecf20Sopenharmony_ci	if (ret) {
6558c2ecf20Sopenharmony_ci		dev_err(dev, "Cannot allocate buffer(s)\n");
6568c2ecf20Sopenharmony_ci		goto free_client;
6578c2ecf20Sopenharmony_ci	}
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	if (pdata->sid < 0)
6608c2ecf20Sopenharmony_ci		prtd->phys = prtd->dma_buffer.addr;
6618c2ecf20Sopenharmony_ci	else
6628c2ecf20Sopenharmony_ci		prtd->phys = prtd->dma_buffer.addr | (pdata->sid << 32);
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci	snd_compr_set_runtime_buffer(stream, &prtd->dma_buffer);
6658c2ecf20Sopenharmony_ci	spin_lock_init(&prtd->lock);
6668c2ecf20Sopenharmony_ci	runtime->private_data = prtd;
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	return 0;
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_cifree_client:
6718c2ecf20Sopenharmony_ci	q6asm_audio_client_free(prtd->audio_client);
6728c2ecf20Sopenharmony_cifree_prtd:
6738c2ecf20Sopenharmony_ci	kfree(prtd);
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci	return ret;
6768c2ecf20Sopenharmony_ci}
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_cistatic int q6asm_dai_compr_free(struct snd_soc_component *component,
6798c2ecf20Sopenharmony_ci				struct snd_compr_stream *stream)
6808c2ecf20Sopenharmony_ci{
6818c2ecf20Sopenharmony_ci	struct snd_compr_runtime *runtime = stream->runtime;
6828c2ecf20Sopenharmony_ci	struct q6asm_dai_rtd *prtd = runtime->private_data;
6838c2ecf20Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = stream->private_data;
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	if (prtd->audio_client) {
6868c2ecf20Sopenharmony_ci		if (prtd->state) {
6878c2ecf20Sopenharmony_ci			q6asm_cmd(prtd->audio_client, prtd->stream_id,
6888c2ecf20Sopenharmony_ci				  CMD_CLOSE);
6898c2ecf20Sopenharmony_ci			if (prtd->next_track_stream_id) {
6908c2ecf20Sopenharmony_ci				q6asm_cmd(prtd->audio_client,
6918c2ecf20Sopenharmony_ci					  prtd->next_track_stream_id,
6928c2ecf20Sopenharmony_ci					  CMD_CLOSE);
6938c2ecf20Sopenharmony_ci			}
6948c2ecf20Sopenharmony_ci		}
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci		snd_dma_free_pages(&prtd->dma_buffer);
6978c2ecf20Sopenharmony_ci		q6asm_unmap_memory_regions(stream->direction,
6988c2ecf20Sopenharmony_ci					   prtd->audio_client);
6998c2ecf20Sopenharmony_ci		q6asm_audio_client_free(prtd->audio_client);
7008c2ecf20Sopenharmony_ci		prtd->audio_client = NULL;
7018c2ecf20Sopenharmony_ci	}
7028c2ecf20Sopenharmony_ci	q6routing_stream_close(rtd->dai_link->id, stream->direction);
7038c2ecf20Sopenharmony_ci	kfree(prtd);
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci	return 0;
7068c2ecf20Sopenharmony_ci}
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_cistatic int __q6asm_dai_compr_set_codec_params(struct snd_soc_component *component,
7098c2ecf20Sopenharmony_ci					      struct snd_compr_stream *stream,
7108c2ecf20Sopenharmony_ci					      struct snd_codec *codec,
7118c2ecf20Sopenharmony_ci					      int stream_id)
7128c2ecf20Sopenharmony_ci{
7138c2ecf20Sopenharmony_ci	struct snd_compr_runtime *runtime = stream->runtime;
7148c2ecf20Sopenharmony_ci	struct q6asm_dai_rtd *prtd = runtime->private_data;
7158c2ecf20Sopenharmony_ci	struct q6asm_flac_cfg flac_cfg;
7168c2ecf20Sopenharmony_ci	struct q6asm_wma_cfg wma_cfg;
7178c2ecf20Sopenharmony_ci	struct q6asm_alac_cfg alac_cfg;
7188c2ecf20Sopenharmony_ci	struct q6asm_ape_cfg ape_cfg;
7198c2ecf20Sopenharmony_ci	unsigned int wma_v9 = 0;
7208c2ecf20Sopenharmony_ci	struct device *dev = component->dev;
7218c2ecf20Sopenharmony_ci	int ret;
7228c2ecf20Sopenharmony_ci	union snd_codec_options *codec_options;
7238c2ecf20Sopenharmony_ci	struct snd_dec_flac *flac;
7248c2ecf20Sopenharmony_ci	struct snd_dec_wma *wma;
7258c2ecf20Sopenharmony_ci	struct snd_dec_alac *alac;
7268c2ecf20Sopenharmony_ci	struct snd_dec_ape *ape;
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	codec_options = &(prtd->codec.options);
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci	memcpy(&prtd->codec, codec, sizeof(*codec));
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	switch (codec->id) {
7338c2ecf20Sopenharmony_ci	case SND_AUDIOCODEC_FLAC:
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci		memset(&flac_cfg, 0x0, sizeof(struct q6asm_flac_cfg));
7368c2ecf20Sopenharmony_ci		flac = &codec_options->flac_d;
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci		flac_cfg.ch_cfg = codec->ch_in;
7398c2ecf20Sopenharmony_ci		flac_cfg.sample_rate = codec->sample_rate;
7408c2ecf20Sopenharmony_ci		flac_cfg.stream_info_present = 1;
7418c2ecf20Sopenharmony_ci		flac_cfg.sample_size = flac->sample_size;
7428c2ecf20Sopenharmony_ci		flac_cfg.min_blk_size = flac->min_blk_size;
7438c2ecf20Sopenharmony_ci		flac_cfg.max_blk_size = flac->max_blk_size;
7448c2ecf20Sopenharmony_ci		flac_cfg.max_frame_size = flac->max_frame_size;
7458c2ecf20Sopenharmony_ci		flac_cfg.min_frame_size = flac->min_frame_size;
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci		ret = q6asm_stream_media_format_block_flac(prtd->audio_client,
7488c2ecf20Sopenharmony_ci							   stream_id,
7498c2ecf20Sopenharmony_ci							   &flac_cfg);
7508c2ecf20Sopenharmony_ci		if (ret < 0) {
7518c2ecf20Sopenharmony_ci			dev_err(dev, "FLAC CMD Format block failed:%d\n", ret);
7528c2ecf20Sopenharmony_ci			return -EIO;
7538c2ecf20Sopenharmony_ci		}
7548c2ecf20Sopenharmony_ci		break;
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	case SND_AUDIOCODEC_WMA:
7578c2ecf20Sopenharmony_ci		wma = &codec_options->wma_d;
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci		memset(&wma_cfg, 0x0, sizeof(struct q6asm_wma_cfg));
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci		wma_cfg.sample_rate =  codec->sample_rate;
7628c2ecf20Sopenharmony_ci		wma_cfg.num_channels = codec->ch_in;
7638c2ecf20Sopenharmony_ci		wma_cfg.bytes_per_sec = codec->bit_rate / 8;
7648c2ecf20Sopenharmony_ci		wma_cfg.block_align = codec->align;
7658c2ecf20Sopenharmony_ci		wma_cfg.bits_per_sample = prtd->bits_per_sample;
7668c2ecf20Sopenharmony_ci		wma_cfg.enc_options = wma->encoder_option;
7678c2ecf20Sopenharmony_ci		wma_cfg.adv_enc_options = wma->adv_encoder_option;
7688c2ecf20Sopenharmony_ci		wma_cfg.adv_enc_options2 = wma->adv_encoder_option2;
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci		if (wma_cfg.num_channels == 1)
7718c2ecf20Sopenharmony_ci			wma_cfg.channel_mask = 4; /* Mono Center */
7728c2ecf20Sopenharmony_ci		else if (wma_cfg.num_channels == 2)
7738c2ecf20Sopenharmony_ci			wma_cfg.channel_mask = 3; /* Stereo FL/FR */
7748c2ecf20Sopenharmony_ci		else
7758c2ecf20Sopenharmony_ci			return -EINVAL;
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci		/* check the codec profile */
7788c2ecf20Sopenharmony_ci		switch (codec->profile) {
7798c2ecf20Sopenharmony_ci		case SND_AUDIOPROFILE_WMA9:
7808c2ecf20Sopenharmony_ci			wma_cfg.fmtag = 0x161;
7818c2ecf20Sopenharmony_ci			wma_v9 = 1;
7828c2ecf20Sopenharmony_ci			break;
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci		case SND_AUDIOPROFILE_WMA10:
7858c2ecf20Sopenharmony_ci			wma_cfg.fmtag = 0x166;
7868c2ecf20Sopenharmony_ci			break;
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci		case SND_AUDIOPROFILE_WMA9_PRO:
7898c2ecf20Sopenharmony_ci			wma_cfg.fmtag = 0x162;
7908c2ecf20Sopenharmony_ci			break;
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci		case SND_AUDIOPROFILE_WMA9_LOSSLESS:
7938c2ecf20Sopenharmony_ci			wma_cfg.fmtag = 0x163;
7948c2ecf20Sopenharmony_ci			break;
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci		case SND_AUDIOPROFILE_WMA10_LOSSLESS:
7978c2ecf20Sopenharmony_ci			wma_cfg.fmtag = 0x167;
7988c2ecf20Sopenharmony_ci			break;
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci		default:
8018c2ecf20Sopenharmony_ci			dev_err(dev, "Unknown WMA profile:%x\n",
8028c2ecf20Sopenharmony_ci				codec->profile);
8038c2ecf20Sopenharmony_ci			return -EIO;
8048c2ecf20Sopenharmony_ci		}
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci		if (wma_v9)
8078c2ecf20Sopenharmony_ci			ret = q6asm_stream_media_format_block_wma_v9(
8088c2ecf20Sopenharmony_ci					prtd->audio_client, stream_id,
8098c2ecf20Sopenharmony_ci					&wma_cfg);
8108c2ecf20Sopenharmony_ci		else
8118c2ecf20Sopenharmony_ci			ret = q6asm_stream_media_format_block_wma_v10(
8128c2ecf20Sopenharmony_ci					prtd->audio_client, stream_id,
8138c2ecf20Sopenharmony_ci					&wma_cfg);
8148c2ecf20Sopenharmony_ci		if (ret < 0) {
8158c2ecf20Sopenharmony_ci			dev_err(dev, "WMA9 CMD failed:%d\n", ret);
8168c2ecf20Sopenharmony_ci			return -EIO;
8178c2ecf20Sopenharmony_ci		}
8188c2ecf20Sopenharmony_ci		break;
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci	case SND_AUDIOCODEC_ALAC:
8218c2ecf20Sopenharmony_ci		memset(&alac_cfg, 0x0, sizeof(alac_cfg));
8228c2ecf20Sopenharmony_ci		alac = &codec_options->alac_d;
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci		alac_cfg.sample_rate = codec->sample_rate;
8258c2ecf20Sopenharmony_ci		alac_cfg.avg_bit_rate = codec->bit_rate;
8268c2ecf20Sopenharmony_ci		alac_cfg.bit_depth = prtd->bits_per_sample;
8278c2ecf20Sopenharmony_ci		alac_cfg.num_channels = codec->ch_in;
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci		alac_cfg.frame_length = alac->frame_length;
8308c2ecf20Sopenharmony_ci		alac_cfg.pb = alac->pb;
8318c2ecf20Sopenharmony_ci		alac_cfg.mb = alac->mb;
8328c2ecf20Sopenharmony_ci		alac_cfg.kb = alac->kb;
8338c2ecf20Sopenharmony_ci		alac_cfg.max_run = alac->max_run;
8348c2ecf20Sopenharmony_ci		alac_cfg.compatible_version = alac->compatible_version;
8358c2ecf20Sopenharmony_ci		alac_cfg.max_frame_bytes = alac->max_frame_bytes;
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci		switch (codec->ch_in) {
8388c2ecf20Sopenharmony_ci		case 1:
8398c2ecf20Sopenharmony_ci			alac_cfg.channel_layout_tag = ALAC_CH_LAYOUT_MONO;
8408c2ecf20Sopenharmony_ci			break;
8418c2ecf20Sopenharmony_ci		case 2:
8428c2ecf20Sopenharmony_ci			alac_cfg.channel_layout_tag = ALAC_CH_LAYOUT_STEREO;
8438c2ecf20Sopenharmony_ci			break;
8448c2ecf20Sopenharmony_ci		}
8458c2ecf20Sopenharmony_ci		ret = q6asm_stream_media_format_block_alac(prtd->audio_client,
8468c2ecf20Sopenharmony_ci							   stream_id,
8478c2ecf20Sopenharmony_ci							   &alac_cfg);
8488c2ecf20Sopenharmony_ci		if (ret < 0) {
8498c2ecf20Sopenharmony_ci			dev_err(dev, "ALAC CMD Format block failed:%d\n", ret);
8508c2ecf20Sopenharmony_ci			return -EIO;
8518c2ecf20Sopenharmony_ci		}
8528c2ecf20Sopenharmony_ci		break;
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci	case SND_AUDIOCODEC_APE:
8558c2ecf20Sopenharmony_ci		memset(&ape_cfg, 0x0, sizeof(ape_cfg));
8568c2ecf20Sopenharmony_ci		ape = &codec_options->ape_d;
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci		ape_cfg.sample_rate = codec->sample_rate;
8598c2ecf20Sopenharmony_ci		ape_cfg.num_channels = codec->ch_in;
8608c2ecf20Sopenharmony_ci		ape_cfg.bits_per_sample = prtd->bits_per_sample;
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci		ape_cfg.compatible_version = ape->compatible_version;
8638c2ecf20Sopenharmony_ci		ape_cfg.compression_level = ape->compression_level;
8648c2ecf20Sopenharmony_ci		ape_cfg.format_flags = ape->format_flags;
8658c2ecf20Sopenharmony_ci		ape_cfg.blocks_per_frame = ape->blocks_per_frame;
8668c2ecf20Sopenharmony_ci		ape_cfg.final_frame_blocks = ape->final_frame_blocks;
8678c2ecf20Sopenharmony_ci		ape_cfg.total_frames = ape->total_frames;
8688c2ecf20Sopenharmony_ci		ape_cfg.seek_table_present = ape->seek_table_present;
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci		ret = q6asm_stream_media_format_block_ape(prtd->audio_client,
8718c2ecf20Sopenharmony_ci							  stream_id,
8728c2ecf20Sopenharmony_ci							  &ape_cfg);
8738c2ecf20Sopenharmony_ci		if (ret < 0) {
8748c2ecf20Sopenharmony_ci			dev_err(dev, "APE CMD Format block failed:%d\n", ret);
8758c2ecf20Sopenharmony_ci			return -EIO;
8768c2ecf20Sopenharmony_ci		}
8778c2ecf20Sopenharmony_ci		break;
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	default:
8808c2ecf20Sopenharmony_ci		break;
8818c2ecf20Sopenharmony_ci	}
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci	return 0;
8848c2ecf20Sopenharmony_ci}
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_cistatic int q6asm_dai_compr_set_params(struct snd_soc_component *component,
8878c2ecf20Sopenharmony_ci				      struct snd_compr_stream *stream,
8888c2ecf20Sopenharmony_ci				      struct snd_compr_params *params)
8898c2ecf20Sopenharmony_ci{
8908c2ecf20Sopenharmony_ci	struct snd_compr_runtime *runtime = stream->runtime;
8918c2ecf20Sopenharmony_ci	struct q6asm_dai_rtd *prtd = runtime->private_data;
8928c2ecf20Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = stream->private_data;
8938c2ecf20Sopenharmony_ci	int dir = stream->direction;
8948c2ecf20Sopenharmony_ci	struct q6asm_dai_data *pdata;
8958c2ecf20Sopenharmony_ci	struct device *dev = component->dev;
8968c2ecf20Sopenharmony_ci	int ret;
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	pdata = snd_soc_component_get_drvdata(component);
8998c2ecf20Sopenharmony_ci	if (!pdata)
9008c2ecf20Sopenharmony_ci		return -EINVAL;
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	if (!prtd || !prtd->audio_client) {
9038c2ecf20Sopenharmony_ci		dev_err(dev, "private data null or audio client freed\n");
9048c2ecf20Sopenharmony_ci		return -EINVAL;
9058c2ecf20Sopenharmony_ci	}
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci	prtd->periods = runtime->fragments;
9088c2ecf20Sopenharmony_ci	prtd->pcm_count = runtime->fragment_size;
9098c2ecf20Sopenharmony_ci	prtd->pcm_size = runtime->fragments * runtime->fragment_size;
9108c2ecf20Sopenharmony_ci	prtd->bits_per_sample = 16;
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	if (dir == SND_COMPRESS_PLAYBACK) {
9138c2ecf20Sopenharmony_ci		ret = q6asm_open_write(prtd->audio_client, prtd->stream_id, params->codec.id,
9148c2ecf20Sopenharmony_ci				params->codec.profile, prtd->bits_per_sample,
9158c2ecf20Sopenharmony_ci				true);
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_ci		if (ret < 0) {
9188c2ecf20Sopenharmony_ci			dev_err(dev, "q6asm_open_write failed\n");
9198c2ecf20Sopenharmony_ci			q6asm_audio_client_free(prtd->audio_client);
9208c2ecf20Sopenharmony_ci			prtd->audio_client = NULL;
9218c2ecf20Sopenharmony_ci			return ret;
9228c2ecf20Sopenharmony_ci		}
9238c2ecf20Sopenharmony_ci	}
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_ci	prtd->session_id = q6asm_get_session_id(prtd->audio_client);
9268c2ecf20Sopenharmony_ci	ret = q6routing_stream_open(rtd->dai_link->id, LEGACY_PCM_MODE,
9278c2ecf20Sopenharmony_ci			      prtd->session_id, dir);
9288c2ecf20Sopenharmony_ci	if (ret) {
9298c2ecf20Sopenharmony_ci		dev_err(dev, "Stream reg failed ret:%d\n", ret);
9308c2ecf20Sopenharmony_ci		return ret;
9318c2ecf20Sopenharmony_ci	}
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	ret = __q6asm_dai_compr_set_codec_params(component, stream,
9348c2ecf20Sopenharmony_ci						 &params->codec,
9358c2ecf20Sopenharmony_ci						 prtd->stream_id);
9368c2ecf20Sopenharmony_ci	if (ret) {
9378c2ecf20Sopenharmony_ci		dev_err(dev, "codec param setup failed ret:%d\n", ret);
9388c2ecf20Sopenharmony_ci		return ret;
9398c2ecf20Sopenharmony_ci	}
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci	ret = q6asm_map_memory_regions(dir, prtd->audio_client, prtd->phys,
9428c2ecf20Sopenharmony_ci				       (prtd->pcm_size / prtd->periods),
9438c2ecf20Sopenharmony_ci				       prtd->periods);
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci	if (ret < 0) {
9468c2ecf20Sopenharmony_ci		dev_err(dev, "Buffer Mapping failed ret:%d\n", ret);
9478c2ecf20Sopenharmony_ci		return -ENOMEM;
9488c2ecf20Sopenharmony_ci	}
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci	prtd->state = Q6ASM_STREAM_RUNNING;
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci	return 0;
9538c2ecf20Sopenharmony_ci}
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_cistatic int q6asm_dai_compr_set_metadata(struct snd_soc_component *component,
9568c2ecf20Sopenharmony_ci					struct snd_compr_stream *stream,
9578c2ecf20Sopenharmony_ci					struct snd_compr_metadata *metadata)
9588c2ecf20Sopenharmony_ci{
9598c2ecf20Sopenharmony_ci	struct snd_compr_runtime *runtime = stream->runtime;
9608c2ecf20Sopenharmony_ci	struct q6asm_dai_rtd *prtd = runtime->private_data;
9618c2ecf20Sopenharmony_ci	int ret = 0;
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci	switch (metadata->key) {
9648c2ecf20Sopenharmony_ci	case SNDRV_COMPRESS_ENCODER_PADDING:
9658c2ecf20Sopenharmony_ci		prtd->trailing_samples_drop = metadata->value[0];
9668c2ecf20Sopenharmony_ci		break;
9678c2ecf20Sopenharmony_ci	case SNDRV_COMPRESS_ENCODER_DELAY:
9688c2ecf20Sopenharmony_ci		prtd->initial_samples_drop = metadata->value[0];
9698c2ecf20Sopenharmony_ci		if (prtd->next_track_stream_id) {
9708c2ecf20Sopenharmony_ci			ret = q6asm_open_write(prtd->audio_client,
9718c2ecf20Sopenharmony_ci					       prtd->next_track_stream_id,
9728c2ecf20Sopenharmony_ci					       prtd->codec.id,
9738c2ecf20Sopenharmony_ci					       prtd->codec.profile,
9748c2ecf20Sopenharmony_ci					       prtd->bits_per_sample,
9758c2ecf20Sopenharmony_ci				       true);
9768c2ecf20Sopenharmony_ci			if (ret < 0) {
9778c2ecf20Sopenharmony_ci				dev_err(component->dev, "q6asm_open_write failed\n");
9788c2ecf20Sopenharmony_ci				return ret;
9798c2ecf20Sopenharmony_ci			}
9808c2ecf20Sopenharmony_ci			ret = __q6asm_dai_compr_set_codec_params(component, stream,
9818c2ecf20Sopenharmony_ci								 &prtd->codec,
9828c2ecf20Sopenharmony_ci								 prtd->next_track_stream_id);
9838c2ecf20Sopenharmony_ci			if (ret < 0) {
9848c2ecf20Sopenharmony_ci				dev_err(component->dev, "q6asm_open_write failed\n");
9858c2ecf20Sopenharmony_ci				return ret;
9868c2ecf20Sopenharmony_ci			}
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci			ret = q6asm_stream_remove_initial_silence(prtd->audio_client,
9898c2ecf20Sopenharmony_ci						    prtd->next_track_stream_id,
9908c2ecf20Sopenharmony_ci						    prtd->initial_samples_drop);
9918c2ecf20Sopenharmony_ci			prtd->next_track_stream_id = 0;
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci		}
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci		break;
9968c2ecf20Sopenharmony_ci	default:
9978c2ecf20Sopenharmony_ci		ret = -EINVAL;
9988c2ecf20Sopenharmony_ci		break;
9998c2ecf20Sopenharmony_ci	}
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci	return ret;
10028c2ecf20Sopenharmony_ci}
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_cistatic int q6asm_dai_compr_trigger(struct snd_soc_component *component,
10058c2ecf20Sopenharmony_ci				   struct snd_compr_stream *stream, int cmd)
10068c2ecf20Sopenharmony_ci{
10078c2ecf20Sopenharmony_ci	struct snd_compr_runtime *runtime = stream->runtime;
10088c2ecf20Sopenharmony_ci	struct q6asm_dai_rtd *prtd = runtime->private_data;
10098c2ecf20Sopenharmony_ci	int ret = 0;
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci	switch (cmd) {
10128c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_START:
10138c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_RESUME:
10148c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
10158c2ecf20Sopenharmony_ci		ret = q6asm_run_nowait(prtd->audio_client, prtd->stream_id,
10168c2ecf20Sopenharmony_ci				       0, 0, 0);
10178c2ecf20Sopenharmony_ci		break;
10188c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_STOP:
10198c2ecf20Sopenharmony_ci		prtd->state = Q6ASM_STREAM_STOPPED;
10208c2ecf20Sopenharmony_ci		ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id,
10218c2ecf20Sopenharmony_ci				       CMD_EOS);
10228c2ecf20Sopenharmony_ci		break;
10238c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_SUSPEND:
10248c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
10258c2ecf20Sopenharmony_ci		ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id,
10268c2ecf20Sopenharmony_ci				       CMD_PAUSE);
10278c2ecf20Sopenharmony_ci		break;
10288c2ecf20Sopenharmony_ci	case SND_COMPR_TRIGGER_NEXT_TRACK:
10298c2ecf20Sopenharmony_ci		prtd->next_track = true;
10308c2ecf20Sopenharmony_ci		prtd->next_track_stream_id = (prtd->stream_id == 1 ? 2 : 1);
10318c2ecf20Sopenharmony_ci		break;
10328c2ecf20Sopenharmony_ci	case SND_COMPR_TRIGGER_DRAIN:
10338c2ecf20Sopenharmony_ci	case SND_COMPR_TRIGGER_PARTIAL_DRAIN:
10348c2ecf20Sopenharmony_ci		prtd->notify_on_drain = true;
10358c2ecf20Sopenharmony_ci		break;
10368c2ecf20Sopenharmony_ci	default:
10378c2ecf20Sopenharmony_ci		ret = -EINVAL;
10388c2ecf20Sopenharmony_ci		break;
10398c2ecf20Sopenharmony_ci	}
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci	return ret;
10428c2ecf20Sopenharmony_ci}
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_cistatic int q6asm_dai_compr_pointer(struct snd_soc_component *component,
10458c2ecf20Sopenharmony_ci				   struct snd_compr_stream *stream,
10468c2ecf20Sopenharmony_ci				   struct snd_compr_tstamp *tstamp)
10478c2ecf20Sopenharmony_ci{
10488c2ecf20Sopenharmony_ci	struct snd_compr_runtime *runtime = stream->runtime;
10498c2ecf20Sopenharmony_ci	struct q6asm_dai_rtd *prtd = runtime->private_data;
10508c2ecf20Sopenharmony_ci	unsigned long flags;
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci	spin_lock_irqsave(&prtd->lock, flags);
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_ci	tstamp->copied_total = prtd->copied_total;
10558c2ecf20Sopenharmony_ci	tstamp->byte_offset = prtd->copied_total % prtd->pcm_size;
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&prtd->lock, flags);
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci	return 0;
10608c2ecf20Sopenharmony_ci}
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_cistatic int q6asm_compr_copy(struct snd_soc_component *component,
10638c2ecf20Sopenharmony_ci			    struct snd_compr_stream *stream, char __user *buf,
10648c2ecf20Sopenharmony_ci			    size_t count)
10658c2ecf20Sopenharmony_ci{
10668c2ecf20Sopenharmony_ci	struct snd_compr_runtime *runtime = stream->runtime;
10678c2ecf20Sopenharmony_ci	struct q6asm_dai_rtd *prtd = runtime->private_data;
10688c2ecf20Sopenharmony_ci	unsigned long flags;
10698c2ecf20Sopenharmony_ci	u32 wflags = 0;
10708c2ecf20Sopenharmony_ci	int avail, bytes_in_flight = 0;
10718c2ecf20Sopenharmony_ci	void *dstn;
10728c2ecf20Sopenharmony_ci	size_t copy;
10738c2ecf20Sopenharmony_ci	u32 app_pointer;
10748c2ecf20Sopenharmony_ci	u32 bytes_received;
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_ci	bytes_received = prtd->bytes_received;
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci	/**
10798c2ecf20Sopenharmony_ci	 * Make sure that next track data pointer is aligned at 32 bit boundary
10808c2ecf20Sopenharmony_ci	 * This is a Mandatory requirement from DSP data buffers alignment
10818c2ecf20Sopenharmony_ci	 */
10828c2ecf20Sopenharmony_ci	if (prtd->next_track)
10838c2ecf20Sopenharmony_ci		bytes_received = ALIGN(prtd->bytes_received, prtd->pcm_count);
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci	app_pointer = bytes_received/prtd->pcm_size;
10868c2ecf20Sopenharmony_ci	app_pointer = bytes_received -  (app_pointer * prtd->pcm_size);
10878c2ecf20Sopenharmony_ci	dstn = prtd->dma_buffer.area + app_pointer;
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	if (count < prtd->pcm_size - app_pointer) {
10908c2ecf20Sopenharmony_ci		if (copy_from_user(dstn, buf, count))
10918c2ecf20Sopenharmony_ci			return -EFAULT;
10928c2ecf20Sopenharmony_ci	} else {
10938c2ecf20Sopenharmony_ci		copy = prtd->pcm_size - app_pointer;
10948c2ecf20Sopenharmony_ci		if (copy_from_user(dstn, buf, copy))
10958c2ecf20Sopenharmony_ci			return -EFAULT;
10968c2ecf20Sopenharmony_ci		if (copy_from_user(prtd->dma_buffer.area, buf + copy,
10978c2ecf20Sopenharmony_ci				   count - copy))
10988c2ecf20Sopenharmony_ci			return -EFAULT;
10998c2ecf20Sopenharmony_ci	}
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci	spin_lock_irqsave(&prtd->lock, flags);
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_ci	bytes_in_flight = prtd->bytes_received - prtd->copied_total;
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_ci	if (prtd->next_track) {
11068c2ecf20Sopenharmony_ci		prtd->next_track = false;
11078c2ecf20Sopenharmony_ci		prtd->copied_total = ALIGN(prtd->copied_total, prtd->pcm_count);
11088c2ecf20Sopenharmony_ci		prtd->bytes_sent = ALIGN(prtd->bytes_sent, prtd->pcm_count);
11098c2ecf20Sopenharmony_ci	}
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ci	prtd->bytes_received = bytes_received + count;
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_ci	/* Kick off the data to dsp if its starving!! */
11148c2ecf20Sopenharmony_ci	if (prtd->state == Q6ASM_STREAM_RUNNING && (bytes_in_flight == 0)) {
11158c2ecf20Sopenharmony_ci		uint32_t bytes_to_write = prtd->pcm_count;
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci		avail = prtd->bytes_received - prtd->bytes_sent;
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_ci		if (avail < prtd->pcm_count)
11208c2ecf20Sopenharmony_ci			bytes_to_write = avail;
11218c2ecf20Sopenharmony_ci
11228c2ecf20Sopenharmony_ci		q6asm_write_async(prtd->audio_client, prtd->stream_id,
11238c2ecf20Sopenharmony_ci				  bytes_to_write, 0, 0, wflags);
11248c2ecf20Sopenharmony_ci		prtd->bytes_sent += bytes_to_write;
11258c2ecf20Sopenharmony_ci	}
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&prtd->lock, flags);
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_ci	return count;
11308c2ecf20Sopenharmony_ci}
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_cistatic int q6asm_dai_compr_mmap(struct snd_soc_component *component,
11338c2ecf20Sopenharmony_ci				struct snd_compr_stream *stream,
11348c2ecf20Sopenharmony_ci				struct vm_area_struct *vma)
11358c2ecf20Sopenharmony_ci{
11368c2ecf20Sopenharmony_ci	struct snd_compr_runtime *runtime = stream->runtime;
11378c2ecf20Sopenharmony_ci	struct q6asm_dai_rtd *prtd = runtime->private_data;
11388c2ecf20Sopenharmony_ci	struct device *dev = component->dev;
11398c2ecf20Sopenharmony_ci
11408c2ecf20Sopenharmony_ci	return dma_mmap_coherent(dev, vma,
11418c2ecf20Sopenharmony_ci			prtd->dma_buffer.area, prtd->dma_buffer.addr,
11428c2ecf20Sopenharmony_ci			prtd->dma_buffer.bytes);
11438c2ecf20Sopenharmony_ci}
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_cistatic int q6asm_dai_compr_get_caps(struct snd_soc_component *component,
11468c2ecf20Sopenharmony_ci				    struct snd_compr_stream *stream,
11478c2ecf20Sopenharmony_ci				    struct snd_compr_caps *caps)
11488c2ecf20Sopenharmony_ci{
11498c2ecf20Sopenharmony_ci	caps->direction = SND_COMPRESS_PLAYBACK;
11508c2ecf20Sopenharmony_ci	caps->min_fragment_size = COMPR_PLAYBACK_MIN_FRAGMENT_SIZE;
11518c2ecf20Sopenharmony_ci	caps->max_fragment_size = COMPR_PLAYBACK_MAX_FRAGMENT_SIZE;
11528c2ecf20Sopenharmony_ci	caps->min_fragments = COMPR_PLAYBACK_MIN_NUM_FRAGMENTS;
11538c2ecf20Sopenharmony_ci	caps->max_fragments = COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
11548c2ecf20Sopenharmony_ci	caps->num_codecs = 5;
11558c2ecf20Sopenharmony_ci	caps->codecs[0] = SND_AUDIOCODEC_MP3;
11568c2ecf20Sopenharmony_ci	caps->codecs[1] = SND_AUDIOCODEC_FLAC;
11578c2ecf20Sopenharmony_ci	caps->codecs[2] = SND_AUDIOCODEC_WMA;
11588c2ecf20Sopenharmony_ci	caps->codecs[3] = SND_AUDIOCODEC_ALAC;
11598c2ecf20Sopenharmony_ci	caps->codecs[4] = SND_AUDIOCODEC_APE;
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci	return 0;
11628c2ecf20Sopenharmony_ci}
11638c2ecf20Sopenharmony_ci
11648c2ecf20Sopenharmony_cistatic int q6asm_dai_compr_get_codec_caps(struct snd_soc_component *component,
11658c2ecf20Sopenharmony_ci					  struct snd_compr_stream *stream,
11668c2ecf20Sopenharmony_ci					  struct snd_compr_codec_caps *codec)
11678c2ecf20Sopenharmony_ci{
11688c2ecf20Sopenharmony_ci	switch (codec->codec) {
11698c2ecf20Sopenharmony_ci	case SND_AUDIOCODEC_MP3:
11708c2ecf20Sopenharmony_ci		*codec = q6asm_compr_caps;
11718c2ecf20Sopenharmony_ci		break;
11728c2ecf20Sopenharmony_ci	default:
11738c2ecf20Sopenharmony_ci		break;
11748c2ecf20Sopenharmony_ci	}
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_ci	return 0;
11778c2ecf20Sopenharmony_ci}
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_cistatic struct snd_compress_ops q6asm_dai_compress_ops = {
11808c2ecf20Sopenharmony_ci	.open		= q6asm_dai_compr_open,
11818c2ecf20Sopenharmony_ci	.free		= q6asm_dai_compr_free,
11828c2ecf20Sopenharmony_ci	.set_params	= q6asm_dai_compr_set_params,
11838c2ecf20Sopenharmony_ci	.set_metadata	= q6asm_dai_compr_set_metadata,
11848c2ecf20Sopenharmony_ci	.pointer	= q6asm_dai_compr_pointer,
11858c2ecf20Sopenharmony_ci	.trigger	= q6asm_dai_compr_trigger,
11868c2ecf20Sopenharmony_ci	.get_caps	= q6asm_dai_compr_get_caps,
11878c2ecf20Sopenharmony_ci	.get_codec_caps	= q6asm_dai_compr_get_codec_caps,
11888c2ecf20Sopenharmony_ci	.mmap		= q6asm_dai_compr_mmap,
11898c2ecf20Sopenharmony_ci	.copy		= q6asm_compr_copy,
11908c2ecf20Sopenharmony_ci};
11918c2ecf20Sopenharmony_ci
11928c2ecf20Sopenharmony_cistatic int q6asm_dai_pcm_new(struct snd_soc_component *component,
11938c2ecf20Sopenharmony_ci			     struct snd_soc_pcm_runtime *rtd)
11948c2ecf20Sopenharmony_ci{
11958c2ecf20Sopenharmony_ci	struct snd_pcm_substream *psubstream, *csubstream;
11968c2ecf20Sopenharmony_ci	struct snd_pcm *pcm = rtd->pcm;
11978c2ecf20Sopenharmony_ci	struct device *dev;
11988c2ecf20Sopenharmony_ci	int size, ret;
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ci	dev = component->dev;
12018c2ecf20Sopenharmony_ci	size = q6asm_dai_hardware_playback.buffer_bytes_max;
12028c2ecf20Sopenharmony_ci	psubstream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
12038c2ecf20Sopenharmony_ci	if (psubstream) {
12048c2ecf20Sopenharmony_ci		ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dev, size,
12058c2ecf20Sopenharmony_ci					  &psubstream->dma_buffer);
12068c2ecf20Sopenharmony_ci		if (ret) {
12078c2ecf20Sopenharmony_ci			dev_err(dev, "Cannot allocate buffer(s)\n");
12088c2ecf20Sopenharmony_ci			return ret;
12098c2ecf20Sopenharmony_ci		}
12108c2ecf20Sopenharmony_ci	}
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci	csubstream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
12138c2ecf20Sopenharmony_ci	if (csubstream) {
12148c2ecf20Sopenharmony_ci		ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dev, size,
12158c2ecf20Sopenharmony_ci					  &csubstream->dma_buffer);
12168c2ecf20Sopenharmony_ci		if (ret) {
12178c2ecf20Sopenharmony_ci			dev_err(dev, "Cannot allocate buffer(s)\n");
12188c2ecf20Sopenharmony_ci			if (psubstream)
12198c2ecf20Sopenharmony_ci				snd_dma_free_pages(&psubstream->dma_buffer);
12208c2ecf20Sopenharmony_ci			return ret;
12218c2ecf20Sopenharmony_ci		}
12228c2ecf20Sopenharmony_ci	}
12238c2ecf20Sopenharmony_ci
12248c2ecf20Sopenharmony_ci	return 0;
12258c2ecf20Sopenharmony_ci}
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_cistatic void q6asm_dai_pcm_free(struct snd_soc_component *component,
12288c2ecf20Sopenharmony_ci			       struct snd_pcm *pcm)
12298c2ecf20Sopenharmony_ci{
12308c2ecf20Sopenharmony_ci	struct snd_pcm_substream *substream;
12318c2ecf20Sopenharmony_ci	int i;
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(pcm->streams); i++) {
12348c2ecf20Sopenharmony_ci		substream = pcm->streams[i].substream;
12358c2ecf20Sopenharmony_ci		if (substream) {
12368c2ecf20Sopenharmony_ci			snd_dma_free_pages(&substream->dma_buffer);
12378c2ecf20Sopenharmony_ci			substream->dma_buffer.area = NULL;
12388c2ecf20Sopenharmony_ci			substream->dma_buffer.addr = 0;
12398c2ecf20Sopenharmony_ci		}
12408c2ecf20Sopenharmony_ci	}
12418c2ecf20Sopenharmony_ci}
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget q6asm_dapm_widgets[] = {
12448c2ecf20Sopenharmony_ci	SND_SOC_DAPM_AIF_IN("MM_DL1", "MultiMedia1 Playback", 0, SND_SOC_NOPM, 0, 0),
12458c2ecf20Sopenharmony_ci	SND_SOC_DAPM_AIF_IN("MM_DL2", "MultiMedia2 Playback", 0, SND_SOC_NOPM, 0, 0),
12468c2ecf20Sopenharmony_ci	SND_SOC_DAPM_AIF_IN("MM_DL3", "MultiMedia3 Playback", 0, SND_SOC_NOPM, 0, 0),
12478c2ecf20Sopenharmony_ci	SND_SOC_DAPM_AIF_IN("MM_DL4", "MultiMedia4 Playback", 0, SND_SOC_NOPM, 0, 0),
12488c2ecf20Sopenharmony_ci	SND_SOC_DAPM_AIF_IN("MM_DL5", "MultiMedia5 Playback", 0, SND_SOC_NOPM, 0, 0),
12498c2ecf20Sopenharmony_ci	SND_SOC_DAPM_AIF_IN("MM_DL6", "MultiMedia6 Playback", 0, SND_SOC_NOPM, 0, 0),
12508c2ecf20Sopenharmony_ci	SND_SOC_DAPM_AIF_IN("MM_DL7", "MultiMedia7 Playback", 0, SND_SOC_NOPM, 0, 0),
12518c2ecf20Sopenharmony_ci	SND_SOC_DAPM_AIF_IN("MM_DL8", "MultiMedia8 Playback", 0, SND_SOC_NOPM, 0, 0),
12528c2ecf20Sopenharmony_ci	SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, SND_SOC_NOPM, 0, 0),
12538c2ecf20Sopenharmony_ci	SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, SND_SOC_NOPM, 0, 0),
12548c2ecf20Sopenharmony_ci	SND_SOC_DAPM_AIF_OUT("MM_UL3", "MultiMedia3 Capture", 0, SND_SOC_NOPM, 0, 0),
12558c2ecf20Sopenharmony_ci	SND_SOC_DAPM_AIF_OUT("MM_UL4", "MultiMedia4 Capture", 0, SND_SOC_NOPM, 0, 0),
12568c2ecf20Sopenharmony_ci	SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, SND_SOC_NOPM, 0, 0),
12578c2ecf20Sopenharmony_ci	SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 Capture", 0, SND_SOC_NOPM, 0, 0),
12588c2ecf20Sopenharmony_ci	SND_SOC_DAPM_AIF_OUT("MM_UL7", "MultiMedia7 Capture", 0, SND_SOC_NOPM, 0, 0),
12598c2ecf20Sopenharmony_ci	SND_SOC_DAPM_AIF_OUT("MM_UL8", "MultiMedia8 Capture", 0, SND_SOC_NOPM, 0, 0),
12608c2ecf20Sopenharmony_ci};
12618c2ecf20Sopenharmony_ci
12628c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver q6asm_fe_dai_component = {
12638c2ecf20Sopenharmony_ci	.name		= DRV_NAME,
12648c2ecf20Sopenharmony_ci	.open		= q6asm_dai_open,
12658c2ecf20Sopenharmony_ci	.hw_params	= q6asm_dai_hw_params,
12668c2ecf20Sopenharmony_ci	.close		= q6asm_dai_close,
12678c2ecf20Sopenharmony_ci	.prepare	= q6asm_dai_prepare,
12688c2ecf20Sopenharmony_ci	.trigger	= q6asm_dai_trigger,
12698c2ecf20Sopenharmony_ci	.pointer	= q6asm_dai_pointer,
12708c2ecf20Sopenharmony_ci	.mmap		= q6asm_dai_mmap,
12718c2ecf20Sopenharmony_ci	.pcm_construct	= q6asm_dai_pcm_new,
12728c2ecf20Sopenharmony_ci	.pcm_destruct	= q6asm_dai_pcm_free,
12738c2ecf20Sopenharmony_ci	.compress_ops	= &q6asm_dai_compress_ops,
12748c2ecf20Sopenharmony_ci	.dapm_widgets	= q6asm_dapm_widgets,
12758c2ecf20Sopenharmony_ci	.num_dapm_widgets = ARRAY_SIZE(q6asm_dapm_widgets),
12768c2ecf20Sopenharmony_ci};
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver q6asm_fe_dais_template[] = {
12798c2ecf20Sopenharmony_ci	Q6ASM_FEDAI_DRIVER(1),
12808c2ecf20Sopenharmony_ci	Q6ASM_FEDAI_DRIVER(2),
12818c2ecf20Sopenharmony_ci	Q6ASM_FEDAI_DRIVER(3),
12828c2ecf20Sopenharmony_ci	Q6ASM_FEDAI_DRIVER(4),
12838c2ecf20Sopenharmony_ci	Q6ASM_FEDAI_DRIVER(5),
12848c2ecf20Sopenharmony_ci	Q6ASM_FEDAI_DRIVER(6),
12858c2ecf20Sopenharmony_ci	Q6ASM_FEDAI_DRIVER(7),
12868c2ecf20Sopenharmony_ci	Q6ASM_FEDAI_DRIVER(8),
12878c2ecf20Sopenharmony_ci};
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_cistatic int of_q6asm_parse_dai_data(struct device *dev,
12908c2ecf20Sopenharmony_ci				    struct q6asm_dai_data *pdata)
12918c2ecf20Sopenharmony_ci{
12928c2ecf20Sopenharmony_ci	struct snd_soc_dai_driver *dai_drv;
12938c2ecf20Sopenharmony_ci	struct snd_soc_pcm_stream empty_stream;
12948c2ecf20Sopenharmony_ci	struct device_node *node;
12958c2ecf20Sopenharmony_ci	int ret, id, dir, idx = 0;
12968c2ecf20Sopenharmony_ci
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_ci	pdata->num_dais = of_get_child_count(dev->of_node);
12998c2ecf20Sopenharmony_ci	if (!pdata->num_dais) {
13008c2ecf20Sopenharmony_ci		dev_err(dev, "No dais found in DT\n");
13018c2ecf20Sopenharmony_ci		return -EINVAL;
13028c2ecf20Sopenharmony_ci	}
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_ci	pdata->dais = devm_kcalloc(dev, pdata->num_dais, sizeof(*dai_drv),
13058c2ecf20Sopenharmony_ci				   GFP_KERNEL);
13068c2ecf20Sopenharmony_ci	if (!pdata->dais)
13078c2ecf20Sopenharmony_ci		return -ENOMEM;
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_ci	memset(&empty_stream, 0, sizeof(empty_stream));
13108c2ecf20Sopenharmony_ci
13118c2ecf20Sopenharmony_ci	for_each_child_of_node(dev->of_node, node) {
13128c2ecf20Sopenharmony_ci		ret = of_property_read_u32(node, "reg", &id);
13138c2ecf20Sopenharmony_ci		if (ret || id >= MAX_SESSIONS || id < 0) {
13148c2ecf20Sopenharmony_ci			dev_err(dev, "valid dai id not found:%d\n", ret);
13158c2ecf20Sopenharmony_ci			continue;
13168c2ecf20Sopenharmony_ci		}
13178c2ecf20Sopenharmony_ci
13188c2ecf20Sopenharmony_ci		dai_drv = &pdata->dais[idx++];
13198c2ecf20Sopenharmony_ci		*dai_drv = q6asm_fe_dais_template[id];
13208c2ecf20Sopenharmony_ci
13218c2ecf20Sopenharmony_ci		ret = of_property_read_u32(node, "direction", &dir);
13228c2ecf20Sopenharmony_ci		if (ret)
13238c2ecf20Sopenharmony_ci			continue;
13248c2ecf20Sopenharmony_ci
13258c2ecf20Sopenharmony_ci		if (dir == Q6ASM_DAI_RX)
13268c2ecf20Sopenharmony_ci			dai_drv->capture = empty_stream;
13278c2ecf20Sopenharmony_ci		else if (dir == Q6ASM_DAI_TX)
13288c2ecf20Sopenharmony_ci			dai_drv->playback = empty_stream;
13298c2ecf20Sopenharmony_ci
13308c2ecf20Sopenharmony_ci		if (of_property_read_bool(node, "is-compress-dai"))
13318c2ecf20Sopenharmony_ci			dai_drv->compress_new = snd_soc_new_compress;
13328c2ecf20Sopenharmony_ci	}
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_ci	return 0;
13358c2ecf20Sopenharmony_ci}
13368c2ecf20Sopenharmony_ci
13378c2ecf20Sopenharmony_cistatic int q6asm_dai_probe(struct platform_device *pdev)
13388c2ecf20Sopenharmony_ci{
13398c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
13408c2ecf20Sopenharmony_ci	struct device_node *node = dev->of_node;
13418c2ecf20Sopenharmony_ci	struct of_phandle_args args;
13428c2ecf20Sopenharmony_ci	struct q6asm_dai_data *pdata;
13438c2ecf20Sopenharmony_ci	int rc;
13448c2ecf20Sopenharmony_ci
13458c2ecf20Sopenharmony_ci	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
13468c2ecf20Sopenharmony_ci	if (!pdata)
13478c2ecf20Sopenharmony_ci		return -ENOMEM;
13488c2ecf20Sopenharmony_ci
13498c2ecf20Sopenharmony_ci	rc = of_parse_phandle_with_fixed_args(node, "iommus", 1, 0, &args);
13508c2ecf20Sopenharmony_ci	if (rc < 0)
13518c2ecf20Sopenharmony_ci		pdata->sid = -1;
13528c2ecf20Sopenharmony_ci	else
13538c2ecf20Sopenharmony_ci		pdata->sid = args.args[0] & SID_MASK_DEFAULT;
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_ci	dev_set_drvdata(dev, pdata);
13568c2ecf20Sopenharmony_ci
13578c2ecf20Sopenharmony_ci	rc = of_q6asm_parse_dai_data(dev, pdata);
13588c2ecf20Sopenharmony_ci	if (rc)
13598c2ecf20Sopenharmony_ci		return rc;
13608c2ecf20Sopenharmony_ci
13618c2ecf20Sopenharmony_ci	return devm_snd_soc_register_component(dev, &q6asm_fe_dai_component,
13628c2ecf20Sopenharmony_ci					       pdata->dais, pdata->num_dais);
13638c2ecf20Sopenharmony_ci}
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci#ifdef CONFIG_OF
13668c2ecf20Sopenharmony_cistatic const struct of_device_id q6asm_dai_device_id[] = {
13678c2ecf20Sopenharmony_ci	{ .compatible = "qcom,q6asm-dais" },
13688c2ecf20Sopenharmony_ci	{},
13698c2ecf20Sopenharmony_ci};
13708c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, q6asm_dai_device_id);
13718c2ecf20Sopenharmony_ci#endif
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_cistatic struct platform_driver q6asm_dai_platform_driver = {
13748c2ecf20Sopenharmony_ci	.driver = {
13758c2ecf20Sopenharmony_ci		.name = "q6asm-dai",
13768c2ecf20Sopenharmony_ci		.of_match_table = of_match_ptr(q6asm_dai_device_id),
13778c2ecf20Sopenharmony_ci	},
13788c2ecf20Sopenharmony_ci	.probe = q6asm_dai_probe,
13798c2ecf20Sopenharmony_ci};
13808c2ecf20Sopenharmony_cimodule_platform_driver(q6asm_dai_platform_driver);
13818c2ecf20Sopenharmony_ci
13828c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Q6ASM dai driver");
13838c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
1384