18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci// Copyright (C) 2019 Spreadtrum Communications Inc.
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
58c2ecf20Sopenharmony_ci#include <linux/dmaengine.h>
68c2ecf20Sopenharmony_ci#include <linux/dma/sprd-dma.h>
78c2ecf20Sopenharmony_ci#include <linux/kernel.h>
88c2ecf20Sopenharmony_ci#include <linux/module.h>
98c2ecf20Sopenharmony_ci#include <sound/pcm.h>
108c2ecf20Sopenharmony_ci#include <sound/pcm_params.h>
118c2ecf20Sopenharmony_ci#include <sound/soc.h>
128c2ecf20Sopenharmony_ci#include <sound/compress_driver.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include "sprd-pcm-dma.h"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#define SPRD_COMPR_DMA_CHANS		2
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci/* Default values if userspace does not set */
198c2ecf20Sopenharmony_ci#define SPRD_COMPR_MIN_FRAGMENT_SIZE	SZ_8K
208c2ecf20Sopenharmony_ci#define SPRD_COMPR_MAX_FRAGMENT_SIZE	SZ_128K
218c2ecf20Sopenharmony_ci#define SPRD_COMPR_MIN_NUM_FRAGMENTS	4
228c2ecf20Sopenharmony_ci#define SPRD_COMPR_MAX_NUM_FRAGMENTS	64
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci/* DSP FIFO size */
258c2ecf20Sopenharmony_ci#define SPRD_COMPR_MCDT_EMPTY_WMK	0
268c2ecf20Sopenharmony_ci#define SPRD_COMPR_MCDT_FIFO_SIZE	512
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci/* Stage 0 IRAM buffer size definition */
298c2ecf20Sopenharmony_ci#define SPRD_COMPR_IRAM_BUF_SIZE	SZ_32K
308c2ecf20Sopenharmony_ci#define SPRD_COMPR_IRAM_INFO_SIZE	(sizeof(struct sprd_compr_playinfo))
318c2ecf20Sopenharmony_ci#define SPRD_COMPR_IRAM_LINKLIST_SIZE	(1024 - SPRD_COMPR_IRAM_INFO_SIZE)
328c2ecf20Sopenharmony_ci#define SPRD_COMPR_IRAM_SIZE		(SPRD_COMPR_IRAM_BUF_SIZE + \
338c2ecf20Sopenharmony_ci					 SPRD_COMPR_IRAM_INFO_SIZE + \
348c2ecf20Sopenharmony_ci					 SPRD_COMPR_IRAM_LINKLIST_SIZE)
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci/* Stage 1 DDR buffer size definition */
378c2ecf20Sopenharmony_ci#define SPRD_COMPR_AREA_BUF_SIZE	SZ_2M
388c2ecf20Sopenharmony_ci#define SPRD_COMPR_AREA_LINKLIST_SIZE	1024
398c2ecf20Sopenharmony_ci#define SPRD_COMPR_AREA_SIZE		(SPRD_COMPR_AREA_BUF_SIZE + \
408c2ecf20Sopenharmony_ci					 SPRD_COMPR_AREA_LINKLIST_SIZE)
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistruct sprd_compr_dma {
438c2ecf20Sopenharmony_ci	struct dma_chan *chan;
448c2ecf20Sopenharmony_ci	struct dma_async_tx_descriptor *desc;
458c2ecf20Sopenharmony_ci	dma_cookie_t cookie;
468c2ecf20Sopenharmony_ci	dma_addr_t phys;
478c2ecf20Sopenharmony_ci	void *virt;
488c2ecf20Sopenharmony_ci	int trans_len;
498c2ecf20Sopenharmony_ci};
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci/*
528c2ecf20Sopenharmony_ci * The Spreadtrum Audio compress offload mode will use 2-stage DMA transfer to
538c2ecf20Sopenharmony_ci * save power. That means we can request 2 dma channels, one for source channel,
548c2ecf20Sopenharmony_ci * and another one for destination channel. Once the source channel's transaction
558c2ecf20Sopenharmony_ci * is done, it will trigger the destination channel's transaction automatically
568c2ecf20Sopenharmony_ci * by hardware signal.
578c2ecf20Sopenharmony_ci *
588c2ecf20Sopenharmony_ci * For 2-stage DMA transfer, we can allocate 2 buffers: IRAM buffer (always
598c2ecf20Sopenharmony_ci * power-on) and DDR buffer. The source channel will transfer data from IRAM
608c2ecf20Sopenharmony_ci * buffer to the DSP fifo to decoding/encoding, once IRAM buffer is empty by
618c2ecf20Sopenharmony_ci * transferring done, the destination channel will start to transfer data from
628c2ecf20Sopenharmony_ci * DDR buffer to IRAM buffer.
638c2ecf20Sopenharmony_ci *
648c2ecf20Sopenharmony_ci * Since the DSP fifo is only 512B, IRAM buffer is allocated by 32K, and DDR
658c2ecf20Sopenharmony_ci * buffer is larger to 2M. That means only the IRAM 32k data is transferred
668c2ecf20Sopenharmony_ci * done, we can wake up the AP system to transfer data from DDR to IRAM, and
678c2ecf20Sopenharmony_ci * other time the AP system can be suspended to save power.
688c2ecf20Sopenharmony_ci */
698c2ecf20Sopenharmony_cistruct sprd_compr_stream {
708c2ecf20Sopenharmony_ci	struct snd_compr_stream *cstream;
718c2ecf20Sopenharmony_ci	struct sprd_compr_ops *compr_ops;
728c2ecf20Sopenharmony_ci	struct sprd_compr_dma dma[SPRD_COMPR_DMA_CHANS];
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	/* DMA engine channel number */
758c2ecf20Sopenharmony_ci	int num_channels;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	/* Stage 0 IRAM buffer */
788c2ecf20Sopenharmony_ci	struct snd_dma_buffer iram_buffer;
798c2ecf20Sopenharmony_ci	/* Stage 1 DDR buffer */
808c2ecf20Sopenharmony_ci	struct snd_dma_buffer compr_buffer;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	/* DSP play information IRAM buffer */
838c2ecf20Sopenharmony_ci	dma_addr_t info_phys;
848c2ecf20Sopenharmony_ci	void *info_area;
858c2ecf20Sopenharmony_ci	int info_size;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	/* Data size copied to IRAM buffer */
888c2ecf20Sopenharmony_ci	int copied_total;
898c2ecf20Sopenharmony_ci	/* Total received data size from userspace */
908c2ecf20Sopenharmony_ci	int received_total;
918c2ecf20Sopenharmony_ci	/* Stage 0 IRAM buffer received data size */
928c2ecf20Sopenharmony_ci	int received_stage0;
938c2ecf20Sopenharmony_ci	/* Stage 1 DDR buffer received data size */
948c2ecf20Sopenharmony_ci	int received_stage1;
958c2ecf20Sopenharmony_ci	/* Stage 1 DDR buffer pointer */
968c2ecf20Sopenharmony_ci	int stage1_pointer;
978c2ecf20Sopenharmony_ci};
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_cistatic int sprd_platform_compr_trigger(struct snd_soc_component *component,
1008c2ecf20Sopenharmony_ci				       struct snd_compr_stream *cstream,
1018c2ecf20Sopenharmony_ci				       int cmd);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_cistatic void sprd_platform_compr_drain_notify(void *arg)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	struct snd_compr_stream *cstream = arg;
1068c2ecf20Sopenharmony_ci	struct snd_compr_runtime *runtime = cstream->runtime;
1078c2ecf20Sopenharmony_ci	struct sprd_compr_stream *stream = runtime->private_data;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	memset(stream->info_area, 0, sizeof(struct sprd_compr_playinfo));
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	snd_compr_drain_notify(cstream);
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_cistatic void sprd_platform_compr_dma_complete(void *data)
1158c2ecf20Sopenharmony_ci{
1168c2ecf20Sopenharmony_ci	struct snd_compr_stream *cstream = data;
1178c2ecf20Sopenharmony_ci	struct snd_compr_runtime *runtime = cstream->runtime;
1188c2ecf20Sopenharmony_ci	struct sprd_compr_stream *stream = runtime->private_data;
1198c2ecf20Sopenharmony_ci	struct sprd_compr_dma *dma = &stream->dma[1];
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	/* Update data size copied to IRAM buffer */
1228c2ecf20Sopenharmony_ci	stream->copied_total += dma->trans_len;
1238c2ecf20Sopenharmony_ci	if (stream->copied_total > stream->received_total)
1248c2ecf20Sopenharmony_ci		stream->copied_total = stream->received_total;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	snd_compr_fragment_elapsed(cstream);
1278c2ecf20Sopenharmony_ci}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_cistatic int sprd_platform_compr_dma_config(struct snd_soc_component *component,
1308c2ecf20Sopenharmony_ci					  struct snd_compr_stream *cstream,
1318c2ecf20Sopenharmony_ci					  struct snd_compr_params *params,
1328c2ecf20Sopenharmony_ci					  int channel)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	struct snd_compr_runtime *runtime = cstream->runtime;
1358c2ecf20Sopenharmony_ci	struct sprd_compr_stream *stream = runtime->private_data;
1368c2ecf20Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
1378c2ecf20Sopenharmony_ci	struct device *dev = component->dev;
1388c2ecf20Sopenharmony_ci	struct sprd_compr_data *data = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
1398c2ecf20Sopenharmony_ci	struct sprd_pcm_dma_params *dma_params = data->dma_params;
1408c2ecf20Sopenharmony_ci	struct sprd_compr_dma *dma = &stream->dma[channel];
1418c2ecf20Sopenharmony_ci	struct dma_slave_config config = { };
1428c2ecf20Sopenharmony_ci	struct sprd_dma_linklist link = { };
1438c2ecf20Sopenharmony_ci	enum dma_transfer_direction dir;
1448c2ecf20Sopenharmony_ci	struct scatterlist *sg, *sgt;
1458c2ecf20Sopenharmony_ci	enum dma_slave_buswidth bus_width;
1468c2ecf20Sopenharmony_ci	int period, period_cnt, sg_num = 2;
1478c2ecf20Sopenharmony_ci	dma_addr_t src_addr, dst_addr;
1488c2ecf20Sopenharmony_ci	unsigned long flags;
1498c2ecf20Sopenharmony_ci	int ret, j;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	if (!dma_params) {
1528c2ecf20Sopenharmony_ci		dev_err(dev, "no dma parameters setting\n");
1538c2ecf20Sopenharmony_ci		return -EINVAL;
1548c2ecf20Sopenharmony_ci	}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	dma->chan = dma_request_slave_channel(dev,
1578c2ecf20Sopenharmony_ci					      dma_params->chan_name[channel]);
1588c2ecf20Sopenharmony_ci	if (!dma->chan) {
1598c2ecf20Sopenharmony_ci		dev_err(dev, "failed to request dma channel\n");
1608c2ecf20Sopenharmony_ci		return -ENODEV;
1618c2ecf20Sopenharmony_ci	}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	sgt = sg = devm_kcalloc(dev, sg_num, sizeof(*sg), GFP_KERNEL);
1648c2ecf20Sopenharmony_ci	if (!sg) {
1658c2ecf20Sopenharmony_ci		ret = -ENOMEM;
1668c2ecf20Sopenharmony_ci		goto sg_err;
1678c2ecf20Sopenharmony_ci	}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	switch (channel) {
1708c2ecf20Sopenharmony_ci	case 0:
1718c2ecf20Sopenharmony_ci		bus_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
1728c2ecf20Sopenharmony_ci		period = (SPRD_COMPR_MCDT_FIFO_SIZE - SPRD_COMPR_MCDT_EMPTY_WMK) * 4;
1738c2ecf20Sopenharmony_ci		period_cnt = params->buffer.fragment_size / period;
1748c2ecf20Sopenharmony_ci		src_addr = stream->iram_buffer.addr;
1758c2ecf20Sopenharmony_ci		dst_addr = dma_params->dev_phys[channel];
1768c2ecf20Sopenharmony_ci		flags = SPRD_DMA_FLAGS(SPRD_DMA_SRC_CHN1,
1778c2ecf20Sopenharmony_ci				       SPRD_DMA_TRANS_DONE_TRG,
1788c2ecf20Sopenharmony_ci				       SPRD_DMA_FRAG_REQ,
1798c2ecf20Sopenharmony_ci				       SPRD_DMA_TRANS_INT);
1808c2ecf20Sopenharmony_ci		break;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	case 1:
1838c2ecf20Sopenharmony_ci		bus_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
1848c2ecf20Sopenharmony_ci		period = params->buffer.fragment_size;
1858c2ecf20Sopenharmony_ci		period_cnt = params->buffer.fragments;
1868c2ecf20Sopenharmony_ci		src_addr = stream->compr_buffer.addr;
1878c2ecf20Sopenharmony_ci		dst_addr = stream->iram_buffer.addr;
1888c2ecf20Sopenharmony_ci		flags = SPRD_DMA_FLAGS(SPRD_DMA_DST_CHN1,
1898c2ecf20Sopenharmony_ci				       SPRD_DMA_TRANS_DONE_TRG,
1908c2ecf20Sopenharmony_ci				       SPRD_DMA_FRAG_REQ,
1918c2ecf20Sopenharmony_ci				       SPRD_DMA_TRANS_INT);
1928c2ecf20Sopenharmony_ci		break;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	default:
1958c2ecf20Sopenharmony_ci		ret = -EINVAL;
1968c2ecf20Sopenharmony_ci		goto config_err;
1978c2ecf20Sopenharmony_ci	}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	dma->trans_len = period * period_cnt;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	config.src_maxburst = period;
2028c2ecf20Sopenharmony_ci	config.src_addr_width = bus_width;
2038c2ecf20Sopenharmony_ci	config.dst_addr_width = bus_width;
2048c2ecf20Sopenharmony_ci	if (cstream->direction == SND_COMPRESS_PLAYBACK) {
2058c2ecf20Sopenharmony_ci		config.src_addr = src_addr;
2068c2ecf20Sopenharmony_ci		config.dst_addr = dst_addr;
2078c2ecf20Sopenharmony_ci		dir = DMA_MEM_TO_DEV;
2088c2ecf20Sopenharmony_ci	} else {
2098c2ecf20Sopenharmony_ci		config.src_addr = dst_addr;
2108c2ecf20Sopenharmony_ci		config.dst_addr = src_addr;
2118c2ecf20Sopenharmony_ci		dir = DMA_DEV_TO_MEM;
2128c2ecf20Sopenharmony_ci	}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	sg_init_table(sgt, sg_num);
2158c2ecf20Sopenharmony_ci	for (j = 0; j < sg_num; j++, sgt++) {
2168c2ecf20Sopenharmony_ci		sg_dma_len(sgt) = dma->trans_len;
2178c2ecf20Sopenharmony_ci		sg_dma_address(sgt) = dst_addr;
2188c2ecf20Sopenharmony_ci	}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	/*
2218c2ecf20Sopenharmony_ci	 * Configure the link-list address for the DMA engine link-list
2228c2ecf20Sopenharmony_ci	 * mode.
2238c2ecf20Sopenharmony_ci	 */
2248c2ecf20Sopenharmony_ci	link.virt_addr = (unsigned long)dma->virt;
2258c2ecf20Sopenharmony_ci	link.phy_addr = dma->phys;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	ret = dmaengine_slave_config(dma->chan, &config);
2288c2ecf20Sopenharmony_ci	if (ret) {
2298c2ecf20Sopenharmony_ci		dev_err(dev,
2308c2ecf20Sopenharmony_ci			"failed to set slave configuration: %d\n", ret);
2318c2ecf20Sopenharmony_ci		goto config_err;
2328c2ecf20Sopenharmony_ci	}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	/*
2358c2ecf20Sopenharmony_ci	 * We configure the DMA request mode, interrupt mode, channel
2368c2ecf20Sopenharmony_ci	 * mode and channel trigger mode by the flags.
2378c2ecf20Sopenharmony_ci	 */
2388c2ecf20Sopenharmony_ci	dma->desc = dma->chan->device->device_prep_slave_sg(dma->chan, sg,
2398c2ecf20Sopenharmony_ci							    sg_num, dir,
2408c2ecf20Sopenharmony_ci							    flags, &link);
2418c2ecf20Sopenharmony_ci	if (!dma->desc) {
2428c2ecf20Sopenharmony_ci		dev_err(dev, "failed to prepare slave sg\n");
2438c2ecf20Sopenharmony_ci		ret = -ENOMEM;
2448c2ecf20Sopenharmony_ci		goto config_err;
2458c2ecf20Sopenharmony_ci	}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	/* Only channel 1 transfer can wake up the AP system. */
2488c2ecf20Sopenharmony_ci	if (!params->no_wake_mode && channel == 1) {
2498c2ecf20Sopenharmony_ci		dma->desc->callback = sprd_platform_compr_dma_complete;
2508c2ecf20Sopenharmony_ci		dma->desc->callback_param = cstream;
2518c2ecf20Sopenharmony_ci	}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	devm_kfree(dev, sg);
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	return 0;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ciconfig_err:
2588c2ecf20Sopenharmony_ci	devm_kfree(dev, sg);
2598c2ecf20Sopenharmony_cisg_err:
2608c2ecf20Sopenharmony_ci	dma_release_channel(dma->chan);
2618c2ecf20Sopenharmony_ci	return ret;
2628c2ecf20Sopenharmony_ci}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_cistatic int sprd_platform_compr_set_params(struct snd_soc_component *component,
2658c2ecf20Sopenharmony_ci					  struct snd_compr_stream *cstream,
2668c2ecf20Sopenharmony_ci					  struct snd_compr_params *params)
2678c2ecf20Sopenharmony_ci{
2688c2ecf20Sopenharmony_ci	struct snd_compr_runtime *runtime = cstream->runtime;
2698c2ecf20Sopenharmony_ci	struct sprd_compr_stream *stream = runtime->private_data;
2708c2ecf20Sopenharmony_ci	struct device *dev = component->dev;
2718c2ecf20Sopenharmony_ci	struct sprd_compr_params compr_params = { };
2728c2ecf20Sopenharmony_ci	int ret;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	/*
2758c2ecf20Sopenharmony_ci	 * Configure the DMA engine 2-stage transfer mode. Channel 1 set as the
2768c2ecf20Sopenharmony_ci	 * destination channel, and channel 0 set as the source channel, that
2778c2ecf20Sopenharmony_ci	 * means once the source channel's transaction is done, it will trigger
2788c2ecf20Sopenharmony_ci	 * the destination channel's transaction automatically.
2798c2ecf20Sopenharmony_ci	 */
2808c2ecf20Sopenharmony_ci	ret = sprd_platform_compr_dma_config(component, cstream, params, 1);
2818c2ecf20Sopenharmony_ci	if (ret) {
2828c2ecf20Sopenharmony_ci		dev_err(dev, "failed to config stage 1 DMA: %d\n", ret);
2838c2ecf20Sopenharmony_ci		return ret;
2848c2ecf20Sopenharmony_ci	}
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	ret = sprd_platform_compr_dma_config(component, cstream, params, 0);
2878c2ecf20Sopenharmony_ci	if (ret) {
2888c2ecf20Sopenharmony_ci		dev_err(dev, "failed to config stage 0 DMA: %d\n", ret);
2898c2ecf20Sopenharmony_ci		goto config_err;
2908c2ecf20Sopenharmony_ci	}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	compr_params.direction = cstream->direction;
2938c2ecf20Sopenharmony_ci	compr_params.sample_rate = params->codec.sample_rate;
2948c2ecf20Sopenharmony_ci	compr_params.channels = stream->num_channels;
2958c2ecf20Sopenharmony_ci	compr_params.info_phys = stream->info_phys;
2968c2ecf20Sopenharmony_ci	compr_params.info_size = stream->info_size;
2978c2ecf20Sopenharmony_ci	compr_params.rate = params->codec.bit_rate;
2988c2ecf20Sopenharmony_ci	compr_params.format = params->codec.id;
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	ret = stream->compr_ops->set_params(cstream->direction, &compr_params);
3018c2ecf20Sopenharmony_ci	if (ret) {
3028c2ecf20Sopenharmony_ci		dev_err(dev, "failed to set parameters: %d\n", ret);
3038c2ecf20Sopenharmony_ci		goto params_err;
3048c2ecf20Sopenharmony_ci	}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	return 0;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ciparams_err:
3098c2ecf20Sopenharmony_ci	dma_release_channel(stream->dma[0].chan);
3108c2ecf20Sopenharmony_ciconfig_err:
3118c2ecf20Sopenharmony_ci	dma_release_channel(stream->dma[1].chan);
3128c2ecf20Sopenharmony_ci	return ret;
3138c2ecf20Sopenharmony_ci}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_cistatic int sprd_platform_compr_open(struct snd_soc_component *component,
3168c2ecf20Sopenharmony_ci				    struct snd_compr_stream *cstream)
3178c2ecf20Sopenharmony_ci{
3188c2ecf20Sopenharmony_ci	struct snd_compr_runtime *runtime = cstream->runtime;
3198c2ecf20Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
3208c2ecf20Sopenharmony_ci	struct device *dev = component->dev;
3218c2ecf20Sopenharmony_ci	struct sprd_compr_data *data = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
3228c2ecf20Sopenharmony_ci	struct sprd_compr_stream *stream;
3238c2ecf20Sopenharmony_ci	struct sprd_compr_callback cb;
3248c2ecf20Sopenharmony_ci	int stream_id = cstream->direction, ret;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
3278c2ecf20Sopenharmony_ci	if (ret)
3288c2ecf20Sopenharmony_ci		return ret;
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	stream = devm_kzalloc(dev, sizeof(*stream), GFP_KERNEL);
3318c2ecf20Sopenharmony_ci	if (!stream)
3328c2ecf20Sopenharmony_ci		return -ENOMEM;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	stream->cstream = cstream;
3358c2ecf20Sopenharmony_ci	stream->num_channels = 2;
3368c2ecf20Sopenharmony_ci	stream->compr_ops = data->ops;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	/*
3398c2ecf20Sopenharmony_ci	 * Allocate the stage 0 IRAM buffer size, including the DMA 0
3408c2ecf20Sopenharmony_ci	 * link-list size and play information of DSP address size.
3418c2ecf20Sopenharmony_ci	 */
3428c2ecf20Sopenharmony_ci	ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_IRAM, dev,
3438c2ecf20Sopenharmony_ci				  SPRD_COMPR_IRAM_SIZE, &stream->iram_buffer);
3448c2ecf20Sopenharmony_ci	if (ret < 0)
3458c2ecf20Sopenharmony_ci		goto err_iram;
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	/* Use to save link-list configuration for DMA 0. */
3488c2ecf20Sopenharmony_ci	stream->dma[0].virt = stream->iram_buffer.area + SPRD_COMPR_IRAM_SIZE;
3498c2ecf20Sopenharmony_ci	stream->dma[0].phys = stream->iram_buffer.addr + SPRD_COMPR_IRAM_SIZE;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	/* Use to update the current data offset of DSP. */
3528c2ecf20Sopenharmony_ci	stream->info_phys = stream->iram_buffer.addr + SPRD_COMPR_IRAM_SIZE +
3538c2ecf20Sopenharmony_ci		SPRD_COMPR_IRAM_LINKLIST_SIZE;
3548c2ecf20Sopenharmony_ci	stream->info_area = stream->iram_buffer.area + SPRD_COMPR_IRAM_SIZE +
3558c2ecf20Sopenharmony_ci		SPRD_COMPR_IRAM_LINKLIST_SIZE;
3568c2ecf20Sopenharmony_ci	stream->info_size = SPRD_COMPR_IRAM_INFO_SIZE;
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	/*
3598c2ecf20Sopenharmony_ci	 * Allocate the stage 1 DDR buffer size, including the DMA 1 link-list
3608c2ecf20Sopenharmony_ci	 * size.
3618c2ecf20Sopenharmony_ci	 */
3628c2ecf20Sopenharmony_ci	ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dev,
3638c2ecf20Sopenharmony_ci				  SPRD_COMPR_AREA_SIZE, &stream->compr_buffer);
3648c2ecf20Sopenharmony_ci	if (ret < 0)
3658c2ecf20Sopenharmony_ci		goto err_compr;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	/* Use to save link-list configuration for DMA 1. */
3688c2ecf20Sopenharmony_ci	stream->dma[1].virt = stream->compr_buffer.area + SPRD_COMPR_AREA_SIZE;
3698c2ecf20Sopenharmony_ci	stream->dma[1].phys = stream->compr_buffer.addr + SPRD_COMPR_AREA_SIZE;
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	cb.drain_notify = sprd_platform_compr_drain_notify;
3728c2ecf20Sopenharmony_ci	cb.drain_data = cstream;
3738c2ecf20Sopenharmony_ci	ret = stream->compr_ops->open(stream_id, &cb);
3748c2ecf20Sopenharmony_ci	if (ret) {
3758c2ecf20Sopenharmony_ci		dev_err(dev, "failed to open compress platform: %d\n", ret);
3768c2ecf20Sopenharmony_ci		goto err_open;
3778c2ecf20Sopenharmony_ci	}
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	runtime->private_data = stream;
3808c2ecf20Sopenharmony_ci	return 0;
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_cierr_open:
3838c2ecf20Sopenharmony_ci	snd_dma_free_pages(&stream->compr_buffer);
3848c2ecf20Sopenharmony_cierr_compr:
3858c2ecf20Sopenharmony_ci	snd_dma_free_pages(&stream->iram_buffer);
3868c2ecf20Sopenharmony_cierr_iram:
3878c2ecf20Sopenharmony_ci	devm_kfree(dev, stream);
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	return ret;
3908c2ecf20Sopenharmony_ci}
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_cistatic int sprd_platform_compr_free(struct snd_soc_component *component,
3938c2ecf20Sopenharmony_ci				    struct snd_compr_stream *cstream)
3948c2ecf20Sopenharmony_ci{
3958c2ecf20Sopenharmony_ci	struct snd_compr_runtime *runtime = cstream->runtime;
3968c2ecf20Sopenharmony_ci	struct sprd_compr_stream *stream = runtime->private_data;
3978c2ecf20Sopenharmony_ci	struct device *dev = component->dev;
3988c2ecf20Sopenharmony_ci	int stream_id = cstream->direction, i;
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	for (i = 0; i < stream->num_channels; i++) {
4018c2ecf20Sopenharmony_ci		struct sprd_compr_dma *dma = &stream->dma[i];
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci		if (dma->chan) {
4048c2ecf20Sopenharmony_ci			dma_release_channel(dma->chan);
4058c2ecf20Sopenharmony_ci			dma->chan = NULL;
4068c2ecf20Sopenharmony_ci		}
4078c2ecf20Sopenharmony_ci	}
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	snd_dma_free_pages(&stream->compr_buffer);
4108c2ecf20Sopenharmony_ci	snd_dma_free_pages(&stream->iram_buffer);
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	stream->compr_ops->close(stream_id);
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	devm_kfree(dev, stream);
4158c2ecf20Sopenharmony_ci	return 0;
4168c2ecf20Sopenharmony_ci}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_cistatic int sprd_platform_compr_trigger(struct snd_soc_component *component,
4198c2ecf20Sopenharmony_ci				       struct snd_compr_stream *cstream,
4208c2ecf20Sopenharmony_ci				       int cmd)
4218c2ecf20Sopenharmony_ci{
4228c2ecf20Sopenharmony_ci	struct snd_compr_runtime *runtime = cstream->runtime;
4238c2ecf20Sopenharmony_ci	struct sprd_compr_stream *stream = runtime->private_data;
4248c2ecf20Sopenharmony_ci	struct device *dev = component->dev;
4258c2ecf20Sopenharmony_ci	int channels = stream->num_channels, ret = 0, i;
4268c2ecf20Sopenharmony_ci	int stream_id = cstream->direction;
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	if (cstream->direction != SND_COMPRESS_PLAYBACK) {
4298c2ecf20Sopenharmony_ci		dev_err(dev, "unsupported compress direction\n");
4308c2ecf20Sopenharmony_ci		return -EINVAL;
4318c2ecf20Sopenharmony_ci	}
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	switch (cmd) {
4348c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_START:
4358c2ecf20Sopenharmony_ci		for (i = channels - 1; i >= 0; i--) {
4368c2ecf20Sopenharmony_ci			struct sprd_compr_dma *dma = &stream->dma[i];
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci			if (!dma->desc)
4398c2ecf20Sopenharmony_ci				continue;
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci			dma->cookie = dmaengine_submit(dma->desc);
4428c2ecf20Sopenharmony_ci			ret = dma_submit_error(dma->cookie);
4438c2ecf20Sopenharmony_ci			if (ret) {
4448c2ecf20Sopenharmony_ci				dev_err(dev, "failed to submit request: %d\n",
4458c2ecf20Sopenharmony_ci					ret);
4468c2ecf20Sopenharmony_ci				return ret;
4478c2ecf20Sopenharmony_ci			}
4488c2ecf20Sopenharmony_ci		}
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci		for (i = channels - 1; i >= 0; i--) {
4518c2ecf20Sopenharmony_ci			struct sprd_compr_dma *dma = &stream->dma[i];
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci			if (dma->chan)
4548c2ecf20Sopenharmony_ci				dma_async_issue_pending(dma->chan);
4558c2ecf20Sopenharmony_ci		}
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci		ret = stream->compr_ops->start(stream_id);
4588c2ecf20Sopenharmony_ci		break;
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_STOP:
4618c2ecf20Sopenharmony_ci		for (i = channels - 1; i >= 0; i--) {
4628c2ecf20Sopenharmony_ci			struct sprd_compr_dma *dma = &stream->dma[i];
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci			if (dma->chan)
4658c2ecf20Sopenharmony_ci				dmaengine_terminate_async(dma->chan);
4668c2ecf20Sopenharmony_ci		}
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci		stream->copied_total = 0;
4698c2ecf20Sopenharmony_ci		stream->stage1_pointer  = 0;
4708c2ecf20Sopenharmony_ci		stream->received_total = 0;
4718c2ecf20Sopenharmony_ci		stream->received_stage0 = 0;
4728c2ecf20Sopenharmony_ci		stream->received_stage1 = 0;
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci		ret = stream->compr_ops->stop(stream_id);
4758c2ecf20Sopenharmony_ci		break;
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_SUSPEND:
4788c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
4798c2ecf20Sopenharmony_ci		for (i = channels - 1; i >= 0; i--) {
4808c2ecf20Sopenharmony_ci			struct sprd_compr_dma *dma = &stream->dma[i];
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci			if (dma->chan)
4838c2ecf20Sopenharmony_ci				dmaengine_pause(dma->chan);
4848c2ecf20Sopenharmony_ci		}
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci		ret = stream->compr_ops->pause(stream_id);
4878c2ecf20Sopenharmony_ci		break;
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_RESUME:
4908c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
4918c2ecf20Sopenharmony_ci		for (i = channels - 1; i >= 0; i--) {
4928c2ecf20Sopenharmony_ci			struct sprd_compr_dma *dma = &stream->dma[i];
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci			if (dma->chan)
4958c2ecf20Sopenharmony_ci				dmaengine_resume(dma->chan);
4968c2ecf20Sopenharmony_ci		}
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci		ret = stream->compr_ops->pause_release(stream_id);
4998c2ecf20Sopenharmony_ci		break;
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	case SND_COMPR_TRIGGER_PARTIAL_DRAIN:
5028c2ecf20Sopenharmony_ci	case SND_COMPR_TRIGGER_DRAIN:
5038c2ecf20Sopenharmony_ci		ret = stream->compr_ops->drain(stream->received_total);
5048c2ecf20Sopenharmony_ci		break;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	default:
5078c2ecf20Sopenharmony_ci		ret = -EINVAL;
5088c2ecf20Sopenharmony_ci		break;
5098c2ecf20Sopenharmony_ci	}
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	return ret;
5128c2ecf20Sopenharmony_ci}
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_cistatic int sprd_platform_compr_pointer(struct snd_soc_component *component,
5158c2ecf20Sopenharmony_ci				       struct snd_compr_stream *cstream,
5168c2ecf20Sopenharmony_ci				       struct snd_compr_tstamp *tstamp)
5178c2ecf20Sopenharmony_ci{
5188c2ecf20Sopenharmony_ci	struct snd_compr_runtime *runtime = cstream->runtime;
5198c2ecf20Sopenharmony_ci	struct sprd_compr_stream *stream = runtime->private_data;
5208c2ecf20Sopenharmony_ci	struct sprd_compr_playinfo *info =
5218c2ecf20Sopenharmony_ci		(struct sprd_compr_playinfo *)stream->info_area;
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	tstamp->copied_total = stream->copied_total;
5248c2ecf20Sopenharmony_ci	tstamp->pcm_io_frames = info->current_data_offset;
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	return 0;
5278c2ecf20Sopenharmony_ci}
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_cistatic int sprd_platform_compr_copy(struct snd_soc_component *component,
5308c2ecf20Sopenharmony_ci				    struct snd_compr_stream *cstream,
5318c2ecf20Sopenharmony_ci				    char __user *buf, size_t count)
5328c2ecf20Sopenharmony_ci{
5338c2ecf20Sopenharmony_ci	struct snd_compr_runtime *runtime = cstream->runtime;
5348c2ecf20Sopenharmony_ci	struct sprd_compr_stream *stream = runtime->private_data;
5358c2ecf20Sopenharmony_ci	int avail_bytes, data_count = count;
5368c2ecf20Sopenharmony_ci	void *dst;
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	/*
5398c2ecf20Sopenharmony_ci	 * We usually set fragment size as 32K, and the stage 0 IRAM buffer
5408c2ecf20Sopenharmony_ci	 * size is 32K too. So if now the received data size of the stage 0
5418c2ecf20Sopenharmony_ci	 * IRAM buffer is less than 32K, that means we have some available
5428c2ecf20Sopenharmony_ci	 * spaces for the stage 0 IRAM buffer.
5438c2ecf20Sopenharmony_ci	 */
5448c2ecf20Sopenharmony_ci	if (stream->received_stage0 < runtime->fragment_size) {
5458c2ecf20Sopenharmony_ci		avail_bytes = runtime->fragment_size - stream->received_stage0;
5468c2ecf20Sopenharmony_ci		dst = stream->iram_buffer.area + stream->received_stage0;
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci		if (avail_bytes >= data_count) {
5498c2ecf20Sopenharmony_ci			/*
5508c2ecf20Sopenharmony_ci			 * Copy data to the stage 0 IRAM buffer directly if
5518c2ecf20Sopenharmony_ci			 * spaces are enough.
5528c2ecf20Sopenharmony_ci			 */
5538c2ecf20Sopenharmony_ci			if (copy_from_user(dst, buf, data_count))
5548c2ecf20Sopenharmony_ci				return -EFAULT;
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci			stream->received_stage0 += data_count;
5578c2ecf20Sopenharmony_ci			stream->copied_total += data_count;
5588c2ecf20Sopenharmony_ci			goto copy_done;
5598c2ecf20Sopenharmony_ci		} else {
5608c2ecf20Sopenharmony_ci			/*
5618c2ecf20Sopenharmony_ci			 * If the data count is larger than the available spaces
5628c2ecf20Sopenharmony_ci			 * of the stage 0 IRAM buffer, we should copy one
5638c2ecf20Sopenharmony_ci			 * partial data to the stage 0 IRAM buffer, and copy
5648c2ecf20Sopenharmony_ci			 * the left to the stage 1 DDR buffer.
5658c2ecf20Sopenharmony_ci			 */
5668c2ecf20Sopenharmony_ci			if (copy_from_user(dst, buf, avail_bytes))
5678c2ecf20Sopenharmony_ci				return -EFAULT;
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci			data_count -= avail_bytes;
5708c2ecf20Sopenharmony_ci			stream->received_stage0 += avail_bytes;
5718c2ecf20Sopenharmony_ci			stream->copied_total += avail_bytes;
5728c2ecf20Sopenharmony_ci			buf += avail_bytes;
5738c2ecf20Sopenharmony_ci		}
5748c2ecf20Sopenharmony_ci	}
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	/*
5778c2ecf20Sopenharmony_ci	 * Copy data to the stage 1 DDR buffer if no spaces for the stage 0 IRAM
5788c2ecf20Sopenharmony_ci	 * buffer.
5798c2ecf20Sopenharmony_ci	 */
5808c2ecf20Sopenharmony_ci	dst = stream->compr_buffer.area + stream->stage1_pointer;
5818c2ecf20Sopenharmony_ci	if (data_count < stream->compr_buffer.bytes - stream->stage1_pointer) {
5828c2ecf20Sopenharmony_ci		if (copy_from_user(dst, buf, data_count))
5838c2ecf20Sopenharmony_ci			return -EFAULT;
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci		stream->stage1_pointer += data_count;
5868c2ecf20Sopenharmony_ci	} else {
5878c2ecf20Sopenharmony_ci		avail_bytes = stream->compr_buffer.bytes - stream->stage1_pointer;
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci		if (copy_from_user(dst, buf, avail_bytes))
5908c2ecf20Sopenharmony_ci			return -EFAULT;
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci		if (copy_from_user(stream->compr_buffer.area, buf + avail_bytes,
5938c2ecf20Sopenharmony_ci				   data_count - avail_bytes))
5948c2ecf20Sopenharmony_ci			return -EFAULT;
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci		stream->stage1_pointer = data_count - avail_bytes;
5978c2ecf20Sopenharmony_ci	}
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	stream->received_stage1 += data_count;
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_cicopy_done:
6028c2ecf20Sopenharmony_ci	/* Update the copied data size. */
6038c2ecf20Sopenharmony_ci	stream->received_total += count;
6048c2ecf20Sopenharmony_ci	return count;
6058c2ecf20Sopenharmony_ci}
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_cistatic int sprd_platform_compr_get_caps(struct snd_soc_component *component,
6088c2ecf20Sopenharmony_ci					struct snd_compr_stream *cstream,
6098c2ecf20Sopenharmony_ci					struct snd_compr_caps *caps)
6108c2ecf20Sopenharmony_ci{
6118c2ecf20Sopenharmony_ci	caps->direction = cstream->direction;
6128c2ecf20Sopenharmony_ci	caps->min_fragment_size = SPRD_COMPR_MIN_FRAGMENT_SIZE;
6138c2ecf20Sopenharmony_ci	caps->max_fragment_size = SPRD_COMPR_MAX_FRAGMENT_SIZE;
6148c2ecf20Sopenharmony_ci	caps->min_fragments = SPRD_COMPR_MIN_NUM_FRAGMENTS;
6158c2ecf20Sopenharmony_ci	caps->max_fragments = SPRD_COMPR_MAX_NUM_FRAGMENTS;
6168c2ecf20Sopenharmony_ci	caps->num_codecs = 2;
6178c2ecf20Sopenharmony_ci	caps->codecs[0] = SND_AUDIOCODEC_MP3;
6188c2ecf20Sopenharmony_ci	caps->codecs[1] = SND_AUDIOCODEC_AAC;
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci	return 0;
6218c2ecf20Sopenharmony_ci}
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_cistatic int
6248c2ecf20Sopenharmony_cisprd_platform_compr_get_codec_caps(struct snd_soc_component *component,
6258c2ecf20Sopenharmony_ci				   struct snd_compr_stream *cstream,
6268c2ecf20Sopenharmony_ci				   struct snd_compr_codec_caps *codec)
6278c2ecf20Sopenharmony_ci{
6288c2ecf20Sopenharmony_ci	switch (codec->codec) {
6298c2ecf20Sopenharmony_ci	case SND_AUDIOCODEC_MP3:
6308c2ecf20Sopenharmony_ci		codec->num_descriptors = 2;
6318c2ecf20Sopenharmony_ci		codec->descriptor[0].max_ch = 2;
6328c2ecf20Sopenharmony_ci		codec->descriptor[0].bit_rate[0] = 320;
6338c2ecf20Sopenharmony_ci		codec->descriptor[0].bit_rate[1] = 128;
6348c2ecf20Sopenharmony_ci		codec->descriptor[0].num_bitrates = 2;
6358c2ecf20Sopenharmony_ci		codec->descriptor[0].profiles = 0;
6368c2ecf20Sopenharmony_ci		codec->descriptor[0].modes = SND_AUDIOCHANMODE_MP3_STEREO;
6378c2ecf20Sopenharmony_ci		codec->descriptor[0].formats = 0;
6388c2ecf20Sopenharmony_ci		break;
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci	case SND_AUDIOCODEC_AAC:
6418c2ecf20Sopenharmony_ci		codec->num_descriptors = 2;
6428c2ecf20Sopenharmony_ci		codec->descriptor[1].max_ch = 2;
6438c2ecf20Sopenharmony_ci		codec->descriptor[1].bit_rate[0] = 320;
6448c2ecf20Sopenharmony_ci		codec->descriptor[1].bit_rate[1] = 128;
6458c2ecf20Sopenharmony_ci		codec->descriptor[1].num_bitrates = 2;
6468c2ecf20Sopenharmony_ci		codec->descriptor[1].profiles = 0;
6478c2ecf20Sopenharmony_ci		codec->descriptor[1].modes = 0;
6488c2ecf20Sopenharmony_ci		codec->descriptor[1].formats = 0;
6498c2ecf20Sopenharmony_ci		break;
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	default:
6528c2ecf20Sopenharmony_ci		return -EINVAL;
6538c2ecf20Sopenharmony_ci	}
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci	return 0;
6568c2ecf20Sopenharmony_ci}
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ciconst struct snd_compress_ops sprd_platform_compress_ops = {
6598c2ecf20Sopenharmony_ci	.open = sprd_platform_compr_open,
6608c2ecf20Sopenharmony_ci	.free = sprd_platform_compr_free,
6618c2ecf20Sopenharmony_ci	.set_params = sprd_platform_compr_set_params,
6628c2ecf20Sopenharmony_ci	.trigger = sprd_platform_compr_trigger,
6638c2ecf20Sopenharmony_ci	.pointer = sprd_platform_compr_pointer,
6648c2ecf20Sopenharmony_ci	.copy = sprd_platform_compr_copy,
6658c2ecf20Sopenharmony_ci	.get_caps = sprd_platform_compr_get_caps,
6668c2ecf20Sopenharmony_ci	.get_codec_caps = sprd_platform_compr_get_codec_caps,
6678c2ecf20Sopenharmony_ci};
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Spreadtrum ASoC Compress Platform Driver");
6708c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
6718c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:compress-platform");
672