2019-03-27 14:47:03 +03:00
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2019 Spreadtrum Communications Inc.
# include <linux/dma-mapping.h>
# include <linux/dmaengine.h>
# include <linux/dma/sprd-dma.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <sound/pcm.h>
# include <sound/pcm_params.h>
# include <sound/soc.h>
# include <sound/compress_driver.h>
# include "sprd-pcm-dma.h"
# define SPRD_COMPR_DMA_CHANS 2
/* Default values if userspace does not set */
# define SPRD_COMPR_MIN_FRAGMENT_SIZE SZ_8K
# define SPRD_COMPR_MAX_FRAGMENT_SIZE SZ_128K
# define SPRD_COMPR_MIN_NUM_FRAGMENTS 4
# define SPRD_COMPR_MAX_NUM_FRAGMENTS 64
/* DSP FIFO size */
# define SPRD_COMPR_MCDT_EMPTY_WMK 0
# define SPRD_COMPR_MCDT_FIFO_SIZE 512
/* Stage 0 IRAM buffer size definition */
# define SPRD_COMPR_IRAM_BUF_SIZE SZ_32K
# define SPRD_COMPR_IRAM_INFO_SIZE (sizeof(struct sprd_compr_playinfo))
# define SPRD_COMPR_IRAM_LINKLIST_SIZE (1024 - SPRD_COMPR_IRAM_INFO_SIZE)
# define SPRD_COMPR_IRAM_SIZE (SPRD_COMPR_IRAM_BUF_SIZE + \
SPRD_COMPR_IRAM_INFO_SIZE + \
SPRD_COMPR_IRAM_LINKLIST_SIZE )
/* Stage 1 DDR buffer size definition */
# define SPRD_COMPR_AREA_BUF_SIZE SZ_2M
# define SPRD_COMPR_AREA_LINKLIST_SIZE 1024
# define SPRD_COMPR_AREA_SIZE (SPRD_COMPR_AREA_BUF_SIZE + \
SPRD_COMPR_AREA_LINKLIST_SIZE )
struct sprd_compr_dma {
struct dma_chan * chan ;
struct dma_async_tx_descriptor * desc ;
dma_cookie_t cookie ;
dma_addr_t phys ;
void * virt ;
int trans_len ;
} ;
/*
* The Spreadtrum Audio compress offload mode will use 2 - stage DMA transfer to
* save power . That means we can request 2 dma channels , one for source channel ,
* and another one for destination channel . Once the source channel ' s transaction
* is done , it will trigger the destination channel ' s transaction automatically
* by hardware signal .
*
* For 2 - stage DMA transfer , we can allocate 2 buffers : IRAM buffer ( always
* power - on ) and DDR buffer . The source channel will transfer data from IRAM
* buffer to the DSP fifo to decoding / encoding , once IRAM buffer is empty by
* transferring done , the destination channel will start to transfer data from
* DDR buffer to IRAM buffer .
*
* Since the DSP fifo is only 512 B , IRAM buffer is allocated by 32 K , and DDR
* buffer is larger to 2 M . That means only the IRAM 32 k data is transferred
* done , we can wake up the AP system to transfer data from DDR to IRAM , and
* other time the AP system can be suspended to save power .
*/
struct sprd_compr_stream {
struct snd_compr_stream * cstream ;
struct sprd_compr_ops * compr_ops ;
struct sprd_compr_dma dma [ SPRD_COMPR_DMA_CHANS ] ;
/* DMA engine channel number */
int num_channels ;
/* Stage 0 IRAM buffer */
struct snd_dma_buffer iram_buffer ;
/* Stage 1 DDR buffer */
struct snd_dma_buffer compr_buffer ;
/* DSP play information IRAM buffer */
dma_addr_t info_phys ;
void * info_area ;
int info_size ;
/* Data size copied to IRAM buffer */
int copied_total ;
/* Total received data size from userspace */
int received_total ;
/* Stage 0 IRAM buffer received data size */
int received_stage0 ;
/* Stage 1 DDR buffer received data size */
int received_stage1 ;
/* Stage 1 DDR buffer pointer */
int stage1_pointer ;
} ;
2020-04-20 10:10:00 +03:00
static int sprd_platform_compr_trigger ( struct snd_soc_component * component ,
struct snd_compr_stream * cstream ,
2019-03-27 14:47:03 +03:00
int cmd ) ;
static void sprd_platform_compr_drain_notify ( void * arg )
{
struct snd_compr_stream * cstream = arg ;
struct snd_compr_runtime * runtime = cstream - > runtime ;
struct sprd_compr_stream * stream = runtime - > private_data ;
memset ( stream - > info_area , 0 , sizeof ( struct sprd_compr_playinfo ) ) ;
2019-04-03 10:47:55 +03:00
snd_compr_drain_notify ( cstream ) ;
2019-03-27 14:47:03 +03:00
}
static void sprd_platform_compr_dma_complete ( void * data )
{
struct snd_compr_stream * cstream = data ;
struct snd_compr_runtime * runtime = cstream - > runtime ;
struct sprd_compr_stream * stream = runtime - > private_data ;
struct sprd_compr_dma * dma = & stream - > dma [ 1 ] ;
/* Update data size copied to IRAM buffer */
stream - > copied_total + = dma - > trans_len ;
if ( stream - > copied_total > stream - > received_total )
stream - > copied_total = stream - > received_total ;
snd_compr_fragment_elapsed ( cstream ) ;
}
2020-04-20 10:10:00 +03:00
static int sprd_platform_compr_dma_config ( struct snd_soc_component * component ,
struct snd_compr_stream * cstream ,
2019-03-27 14:47:03 +03:00
struct snd_compr_params * params ,
int channel )
{
struct snd_compr_runtime * runtime = cstream - > runtime ;
struct sprd_compr_stream * stream = runtime - > private_data ;
struct snd_soc_pcm_runtime * rtd = cstream - > private_data ;
struct device * dev = component - > dev ;
2020-03-23 08:20:44 +03:00
struct sprd_compr_data * data = snd_soc_dai_get_drvdata ( asoc_rtd_to_cpu ( rtd , 0 ) ) ;
2019-03-27 14:47:03 +03:00
struct sprd_pcm_dma_params * dma_params = data - > dma_params ;
struct sprd_compr_dma * dma = & stream - > dma [ channel ] ;
struct dma_slave_config config = { } ;
struct sprd_dma_linklist link = { } ;
enum dma_transfer_direction dir ;
struct scatterlist * sg , * sgt ;
enum dma_slave_buswidth bus_width ;
int period , period_cnt , sg_num = 2 ;
dma_addr_t src_addr , dst_addr ;
unsigned long flags ;
int ret , j ;
if ( ! dma_params ) {
dev_err ( dev , " no dma parameters setting \n " ) ;
return - EINVAL ;
}
dma - > chan = dma_request_slave_channel ( dev ,
dma_params - > chan_name [ channel ] ) ;
if ( ! dma - > chan ) {
dev_err ( dev , " failed to request dma channel \n " ) ;
return - ENODEV ;
}
sgt = sg = devm_kcalloc ( dev , sg_num , sizeof ( * sg ) , GFP_KERNEL ) ;
if ( ! sg ) {
ret = - ENOMEM ;
goto sg_err ;
}
switch ( channel ) {
case 0 :
bus_width = DMA_SLAVE_BUSWIDTH_4_BYTES ;
period = ( SPRD_COMPR_MCDT_FIFO_SIZE - SPRD_COMPR_MCDT_EMPTY_WMK ) * 4 ;
period_cnt = params - > buffer . fragment_size / period ;
src_addr = stream - > iram_buffer . addr ;
dst_addr = dma_params - > dev_phys [ channel ] ;
flags = SPRD_DMA_FLAGS ( SPRD_DMA_SRC_CHN1 ,
SPRD_DMA_TRANS_DONE_TRG ,
SPRD_DMA_FRAG_REQ ,
SPRD_DMA_TRANS_INT ) ;
break ;
case 1 :
bus_width = DMA_SLAVE_BUSWIDTH_2_BYTES ;
period = params - > buffer . fragment_size ;
period_cnt = params - > buffer . fragments ;
src_addr = stream - > compr_buffer . addr ;
dst_addr = stream - > iram_buffer . addr ;
flags = SPRD_DMA_FLAGS ( SPRD_DMA_DST_CHN1 ,
SPRD_DMA_TRANS_DONE_TRG ,
SPRD_DMA_FRAG_REQ ,
SPRD_DMA_TRANS_INT ) ;
break ;
default :
ret = - EINVAL ;
goto config_err ;
}
dma - > trans_len = period * period_cnt ;
config . src_maxburst = period ;
config . src_addr_width = bus_width ;
config . dst_addr_width = bus_width ;
if ( cstream - > direction = = SND_COMPRESS_PLAYBACK ) {
config . src_addr = src_addr ;
config . dst_addr = dst_addr ;
dir = DMA_MEM_TO_DEV ;
} else {
config . src_addr = dst_addr ;
config . dst_addr = src_addr ;
dir = DMA_DEV_TO_MEM ;
}
sg_init_table ( sgt , sg_num ) ;
for ( j = 0 ; j < sg_num ; j + + , sgt + + ) {
sg_dma_len ( sgt ) = dma - > trans_len ;
sg_dma_address ( sgt ) = dst_addr ;
}
/*
* Configure the link - list address for the DMA engine link - list
* mode .
*/
link . virt_addr = ( unsigned long ) dma - > virt ;
link . phy_addr = dma - > phys ;
ret = dmaengine_slave_config ( dma - > chan , & config ) ;
if ( ret ) {
dev_err ( dev ,
" failed to set slave configuration: %d \n " , ret ) ;
goto config_err ;
}
/*
* We configure the DMA request mode , interrupt mode , channel
* mode and channel trigger mode by the flags .
*/
dma - > desc = dma - > chan - > device - > device_prep_slave_sg ( dma - > chan , sg ,
sg_num , dir ,
flags , & link ) ;
if ( ! dma - > desc ) {
dev_err ( dev , " failed to prepare slave sg \n " ) ;
ret = - ENOMEM ;
goto config_err ;
}
/* Only channel 1 transfer can wake up the AP system. */
if ( ! params - > no_wake_mode & & channel = = 1 ) {
dma - > desc - > callback = sprd_platform_compr_dma_complete ;
dma - > desc - > callback_param = cstream ;
}
devm_kfree ( dev , sg ) ;
return 0 ;
config_err :
devm_kfree ( dev , sg ) ;
sg_err :
dma_release_channel ( dma - > chan ) ;
return ret ;
}
2020-04-20 10:10:00 +03:00
static int sprd_platform_compr_set_params ( struct snd_soc_component * component ,
struct snd_compr_stream * cstream ,
2019-03-27 14:47:03 +03:00
struct snd_compr_params * params )
{
struct snd_compr_runtime * runtime = cstream - > runtime ;
struct sprd_compr_stream * stream = runtime - > private_data ;
struct device * dev = component - > dev ;
struct sprd_compr_params compr_params = { } ;
int ret ;
/*
* Configure the DMA engine 2 - stage transfer mode . Channel 1 set as the
* destination channel , and channel 0 set as the source channel , that
* means once the source channel ' s transaction is done , it will trigger
* the destination channel ' s transaction automatically .
*/
2020-04-20 10:10:00 +03:00
ret = sprd_platform_compr_dma_config ( component , cstream , params , 1 ) ;
2019-03-27 14:47:03 +03:00
if ( ret ) {
2019-04-04 10:56:03 +03:00
dev_err ( dev , " failed to config stage 1 DMA: %d \n " , ret ) ;
2019-03-27 14:47:03 +03:00
return ret ;
}
2020-04-20 10:10:00 +03:00
ret = sprd_platform_compr_dma_config ( component , cstream , params , 0 ) ;
2019-03-27 14:47:03 +03:00
if ( ret ) {
2019-04-04 10:56:03 +03:00
dev_err ( dev , " failed to config stage 0 DMA: %d \n " , ret ) ;
2019-03-27 14:47:03 +03:00
goto config_err ;
}
compr_params . direction = cstream - > direction ;
compr_params . sample_rate = params - > codec . sample_rate ;
compr_params . channels = stream - > num_channels ;
compr_params . info_phys = stream - > info_phys ;
compr_params . info_size = stream - > info_size ;
compr_params . rate = params - > codec . bit_rate ;
compr_params . format = params - > codec . id ;
ret = stream - > compr_ops - > set_params ( cstream - > direction , & compr_params ) ;
if ( ret ) {
dev_err ( dev , " failed to set parameters: %d \n " , ret ) ;
goto params_err ;
}
return 0 ;
params_err :
dma_release_channel ( stream - > dma [ 0 ] . chan ) ;
config_err :
dma_release_channel ( stream - > dma [ 1 ] . chan ) ;
return ret ;
}
2020-04-20 10:10:00 +03:00
static int sprd_platform_compr_open ( struct snd_soc_component * component ,
struct snd_compr_stream * cstream )
2019-03-27 14:47:03 +03:00
{
struct snd_compr_runtime * runtime = cstream - > runtime ;
struct snd_soc_pcm_runtime * rtd = cstream - > private_data ;
struct device * dev = component - > dev ;
2020-03-23 08:20:44 +03:00
struct sprd_compr_data * data = snd_soc_dai_get_drvdata ( asoc_rtd_to_cpu ( rtd , 0 ) ) ;
2019-03-27 14:47:03 +03:00
struct sprd_compr_stream * stream ;
struct sprd_compr_callback cb ;
int stream_id = cstream - > direction , ret ;
ret = dma_coerce_mask_and_coherent ( dev , DMA_BIT_MASK ( 32 ) ) ;
if ( ret )
return ret ;
stream = devm_kzalloc ( dev , sizeof ( * stream ) , GFP_KERNEL ) ;
if ( ! stream )
return - ENOMEM ;
stream - > cstream = cstream ;
stream - > num_channels = 2 ;
stream - > compr_ops = data - > ops ;
/*
* Allocate the stage 0 IRAM buffer size , including the DMA 0
* link - list size and play information of DSP address size .
*/
ret = snd_dma_alloc_pages ( SNDRV_DMA_TYPE_DEV_IRAM , dev ,
SPRD_COMPR_IRAM_SIZE , & stream - > iram_buffer ) ;
if ( ret < 0 )
goto err_iram ;
/* Use to save link-list configuration for DMA 0. */
stream - > dma [ 0 ] . virt = stream - > iram_buffer . area + SPRD_COMPR_IRAM_SIZE ;
stream - > dma [ 0 ] . phys = stream - > iram_buffer . addr + SPRD_COMPR_IRAM_SIZE ;
/* Use to update the current data offset of DSP. */
stream - > info_phys = stream - > iram_buffer . addr + SPRD_COMPR_IRAM_SIZE +
SPRD_COMPR_IRAM_LINKLIST_SIZE ;
stream - > info_area = stream - > iram_buffer . area + SPRD_COMPR_IRAM_SIZE +
SPRD_COMPR_IRAM_LINKLIST_SIZE ;
stream - > info_size = SPRD_COMPR_IRAM_INFO_SIZE ;
/*
* Allocate the stage 1 DDR buffer size , including the DMA 1 link - list
* size .
*/
ret = snd_dma_alloc_pages ( SNDRV_DMA_TYPE_DEV , dev ,
SPRD_COMPR_AREA_SIZE , & stream - > compr_buffer ) ;
if ( ret < 0 )
goto err_compr ;
/* Use to save link-list configuration for DMA 1. */
stream - > dma [ 1 ] . virt = stream - > compr_buffer . area + SPRD_COMPR_AREA_SIZE ;
stream - > dma [ 1 ] . phys = stream - > compr_buffer . addr + SPRD_COMPR_AREA_SIZE ;
cb . drain_notify = sprd_platform_compr_drain_notify ;
cb . drain_data = cstream ;
ret = stream - > compr_ops - > open ( stream_id , & cb ) ;
if ( ret ) {
dev_err ( dev , " failed to open compress platform: %d \n " , ret ) ;
goto err_open ;
}
runtime - > private_data = stream ;
return 0 ;
err_open :
snd_dma_free_pages ( & stream - > compr_buffer ) ;
err_compr :
snd_dma_free_pages ( & stream - > iram_buffer ) ;
err_iram :
devm_kfree ( dev , stream ) ;
return ret ;
}
2020-04-20 10:10:00 +03:00
static int sprd_platform_compr_free ( struct snd_soc_component * component ,
struct snd_compr_stream * cstream )
2019-03-27 14:47:03 +03:00
{
struct snd_compr_runtime * runtime = cstream - > runtime ;
struct sprd_compr_stream * stream = runtime - > private_data ;
struct device * dev = component - > dev ;
int stream_id = cstream - > direction , i ;
for ( i = 0 ; i < stream - > num_channels ; i + + ) {
struct sprd_compr_dma * dma = & stream - > dma [ i ] ;
if ( dma - > chan ) {
dma_release_channel ( dma - > chan ) ;
dma - > chan = NULL ;
}
}
snd_dma_free_pages ( & stream - > compr_buffer ) ;
snd_dma_free_pages ( & stream - > iram_buffer ) ;
stream - > compr_ops - > close ( stream_id ) ;
devm_kfree ( dev , stream ) ;
return 0 ;
}
2020-04-20 10:10:00 +03:00
static int sprd_platform_compr_trigger ( struct snd_soc_component * component ,
struct snd_compr_stream * cstream ,
2019-03-27 14:47:03 +03:00
int cmd )
{
struct snd_compr_runtime * runtime = cstream - > runtime ;
struct sprd_compr_stream * stream = runtime - > private_data ;
struct device * dev = component - > dev ;
int channels = stream - > num_channels , ret = 0 , i ;
int stream_id = cstream - > direction ;
if ( cstream - > direction ! = SND_COMPRESS_PLAYBACK ) {
dev_err ( dev , " unsupported compress direction \n " ) ;
return - EINVAL ;
}
switch ( cmd ) {
case SNDRV_PCM_TRIGGER_START :
for ( i = channels - 1 ; i > = 0 ; i - - ) {
struct sprd_compr_dma * dma = & stream - > dma [ i ] ;
if ( ! dma - > desc )
continue ;
dma - > cookie = dmaengine_submit ( dma - > desc ) ;
ret = dma_submit_error ( dma - > cookie ) ;
if ( ret ) {
dev_err ( dev , " failed to submit request: %d \n " ,
ret ) ;
return ret ;
}
}
for ( i = channels - 1 ; i > = 0 ; i - - ) {
struct sprd_compr_dma * dma = & stream - > dma [ i ] ;
if ( dma - > chan )
dma_async_issue_pending ( dma - > chan ) ;
}
ret = stream - > compr_ops - > start ( stream_id ) ;
break ;
case SNDRV_PCM_TRIGGER_STOP :
for ( i = channels - 1 ; i > = 0 ; i - - ) {
struct sprd_compr_dma * dma = & stream - > dma [ i ] ;
if ( dma - > chan )
dmaengine_terminate_async ( dma - > chan ) ;
}
stream - > copied_total = 0 ;
stream - > stage1_pointer = 0 ;
stream - > received_total = 0 ;
stream - > received_stage0 = 0 ;
stream - > received_stage1 = 0 ;
ret = stream - > compr_ops - > stop ( stream_id ) ;
break ;
case SNDRV_PCM_TRIGGER_SUSPEND :
case SNDRV_PCM_TRIGGER_PAUSE_PUSH :
for ( i = channels - 1 ; i > = 0 ; i - - ) {
struct sprd_compr_dma * dma = & stream - > dma [ i ] ;
if ( dma - > chan )
dmaengine_pause ( dma - > chan ) ;
}
ret = stream - > compr_ops - > pause ( stream_id ) ;
break ;
case SNDRV_PCM_TRIGGER_RESUME :
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE :
for ( i = channels - 1 ; i > = 0 ; i - - ) {
struct sprd_compr_dma * dma = & stream - > dma [ i ] ;
if ( dma - > chan )
dmaengine_resume ( dma - > chan ) ;
}
ret = stream - > compr_ops - > pause_release ( stream_id ) ;
break ;
case SND_COMPR_TRIGGER_PARTIAL_DRAIN :
case SND_COMPR_TRIGGER_DRAIN :
ret = stream - > compr_ops - > drain ( stream - > received_total ) ;
break ;
default :
ret = - EINVAL ;
break ;
}
return ret ;
}
2020-04-20 10:10:00 +03:00
static int sprd_platform_compr_pointer ( struct snd_soc_component * component ,
struct snd_compr_stream * cstream ,
2019-03-27 14:47:03 +03:00
struct snd_compr_tstamp * tstamp )
{
struct snd_compr_runtime * runtime = cstream - > runtime ;
struct sprd_compr_stream * stream = runtime - > private_data ;
struct sprd_compr_playinfo * info =
( struct sprd_compr_playinfo * ) stream - > info_area ;
tstamp - > copied_total = stream - > copied_total ;
tstamp - > pcm_io_frames = info - > current_data_offset ;
return 0 ;
}
2020-04-20 10:10:00 +03:00
static int sprd_platform_compr_copy ( struct snd_soc_component * component ,
struct snd_compr_stream * cstream ,
2019-03-27 14:47:03 +03:00
char __user * buf , size_t count )
{
struct snd_compr_runtime * runtime = cstream - > runtime ;
struct sprd_compr_stream * stream = runtime - > private_data ;
int avail_bytes , data_count = count ;
void * dst ;
/*
* We usually set fragment size as 32 K , and the stage 0 IRAM buffer
* size is 32 K too . So if now the received data size of the stage 0
* IRAM buffer is less than 32 K , that means we have some available
* spaces for the stage 0 IRAM buffer .
*/
if ( stream - > received_stage0 < runtime - > fragment_size ) {
avail_bytes = runtime - > fragment_size - stream - > received_stage0 ;
dst = stream - > iram_buffer . area + stream - > received_stage0 ;
if ( avail_bytes > = data_count ) {
/*
* Copy data to the stage 0 IRAM buffer directly if
* spaces are enough .
*/
if ( copy_from_user ( dst , buf , data_count ) )
return - EFAULT ;
stream - > received_stage0 + = data_count ;
stream - > copied_total + = data_count ;
goto copy_done ;
} else {
/*
* If the data count is larger than the available spaces
2020-08-08 04:22:09 +03:00
* of the stage 0 IRAM buffer , we should copy one
2019-03-27 14:47:03 +03:00
* partial data to the stage 0 IRAM buffer , and copy
* the left to the stage 1 DDR buffer .
*/
if ( copy_from_user ( dst , buf , avail_bytes ) )
return - EFAULT ;
data_count - = avail_bytes ;
stream - > received_stage0 + = avail_bytes ;
stream - > copied_total + = avail_bytes ;
buf + = avail_bytes ;
}
}
/*
* Copy data to the stage 1 DDR buffer if no spaces for the stage 0 IRAM
* buffer .
*/
dst = stream - > compr_buffer . area + stream - > stage1_pointer ;
if ( data_count < stream - > compr_buffer . bytes - stream - > stage1_pointer ) {
if ( copy_from_user ( dst , buf , data_count ) )
return - EFAULT ;
stream - > stage1_pointer + = data_count ;
} else {
avail_bytes = stream - > compr_buffer . bytes - stream - > stage1_pointer ;
if ( copy_from_user ( dst , buf , avail_bytes ) )
return - EFAULT ;
if ( copy_from_user ( stream - > compr_buffer . area , buf + avail_bytes ,
data_count - avail_bytes ) )
return - EFAULT ;
stream - > stage1_pointer = data_count - avail_bytes ;
}
stream - > received_stage1 + = data_count ;
copy_done :
/* Update the copied data size. */
stream - > received_total + = count ;
return count ;
}
2020-04-20 10:10:00 +03:00
static int sprd_platform_compr_get_caps ( struct snd_soc_component * component ,
struct snd_compr_stream * cstream ,
2019-03-27 14:47:03 +03:00
struct snd_compr_caps * caps )
{
caps - > direction = cstream - > direction ;
caps - > min_fragment_size = SPRD_COMPR_MIN_FRAGMENT_SIZE ;
caps - > max_fragment_size = SPRD_COMPR_MAX_FRAGMENT_SIZE ;
caps - > min_fragments = SPRD_COMPR_MIN_NUM_FRAGMENTS ;
caps - > max_fragments = SPRD_COMPR_MAX_NUM_FRAGMENTS ;
caps - > num_codecs = 2 ;
caps - > codecs [ 0 ] = SND_AUDIOCODEC_MP3 ;
caps - > codecs [ 1 ] = SND_AUDIOCODEC_AAC ;
return 0 ;
}
static int
2020-04-20 10:10:00 +03:00
sprd_platform_compr_get_codec_caps ( struct snd_soc_component * component ,
struct snd_compr_stream * cstream ,
2019-03-27 14:47:03 +03:00
struct snd_compr_codec_caps * codec )
{
switch ( codec - > codec ) {
case SND_AUDIOCODEC_MP3 :
codec - > num_descriptors = 2 ;
codec - > descriptor [ 0 ] . max_ch = 2 ;
codec - > descriptor [ 0 ] . bit_rate [ 0 ] = 320 ;
codec - > descriptor [ 0 ] . bit_rate [ 1 ] = 128 ;
codec - > descriptor [ 0 ] . num_bitrates = 2 ;
codec - > descriptor [ 0 ] . profiles = 0 ;
codec - > descriptor [ 0 ] . modes = SND_AUDIOCHANMODE_MP3_STEREO ;
codec - > descriptor [ 0 ] . formats = 0 ;
break ;
case SND_AUDIOCODEC_AAC :
codec - > num_descriptors = 2 ;
codec - > descriptor [ 1 ] . max_ch = 2 ;
codec - > descriptor [ 1 ] . bit_rate [ 0 ] = 320 ;
codec - > descriptor [ 1 ] . bit_rate [ 1 ] = 128 ;
codec - > descriptor [ 1 ] . num_bitrates = 2 ;
codec - > descriptor [ 1 ] . profiles = 0 ;
codec - > descriptor [ 1 ] . modes = 0 ;
codec - > descriptor [ 1 ] . formats = 0 ;
break ;
default :
return - EINVAL ;
}
return 0 ;
}
2020-04-20 10:10:00 +03:00
const struct snd_compress_ops sprd_platform_compress_ops = {
2019-03-27 14:47:03 +03:00
. open = sprd_platform_compr_open ,
. free = sprd_platform_compr_free ,
. set_params = sprd_platform_compr_set_params ,
. trigger = sprd_platform_compr_trigger ,
. pointer = sprd_platform_compr_pointer ,
. copy = sprd_platform_compr_copy ,
. get_caps = sprd_platform_compr_get_caps ,
. get_codec_caps = sprd_platform_compr_get_codec_caps ,
} ;
MODULE_DESCRIPTION ( " Spreadtrum ASoC Compress Platform Driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_ALIAS ( " platform:compress-platform " ) ;