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