2018-07-24 15:48:31 +03:00
// SPDX-License-Identifier: GPL-2.0
//
// Freescale ASRC ALSA SoC Platform (DMA) driver
//
// Copyright (C) 2014 Freescale Semiconductor, Inc.
//
// Author: Nicolin Chen <nicoleotsuka@gmail.com>
2014-07-29 14:08:53 +04:00
# include <linux/dma-mapping.h>
# include <linux/module.h>
2022-04-14 19:22:37 +03:00
# include <linux/dma/imx-dma.h>
2014-07-29 14:08:53 +04:00
# include <sound/dmaengine_pcm.h>
# include <sound/pcm_params.h>
2020-04-16 15:25:35 +03:00
# include "fsl_asrc_common.h"
2014-07-29 14:08:53 +04:00
# define FSL_ASRC_DMABUF_SIZE (256 * 1024)
2019-09-27 04:46:12 +03:00
static struct snd_pcm_hardware snd_imx_hardware = {
2014-07-29 14:08:53 +04:00
. info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP |
2019-09-27 04:46:12 +03:00
SNDRV_PCM_INFO_MMAP_VALID ,
2014-07-29 14:08:53 +04:00
. buffer_bytes_max = FSL_ASRC_DMABUF_SIZE ,
. period_bytes_min = 128 ,
. period_bytes_max = 65535 , /* Limited by SDMA engine */
. periods_min = 2 ,
. periods_max = 255 ,
. fifo_size = 0 ,
} ;
static bool filter ( struct dma_chan * chan , void * param )
{
if ( ! imx_dma_is_general_purpose ( chan ) )
return false ;
chan - > private = param ;
return true ;
}
static void fsl_asrc_dma_complete ( void * arg )
{
struct snd_pcm_substream * substream = arg ;
struct snd_pcm_runtime * runtime = substream - > runtime ;
struct fsl_asrc_pair * pair = runtime - > private_data ;
pair - > pos + = snd_pcm_lib_period_bytes ( substream ) ;
if ( pair - > pos > = snd_pcm_lib_buffer_bytes ( substream ) )
pair - > pos = 0 ;
snd_pcm_period_elapsed ( substream ) ;
}
2019-10-02 08:34:43 +03:00
static int fsl_asrc_dma_prepare_and_submit ( struct snd_pcm_substream * substream ,
struct snd_soc_component * component )
2014-07-29 14:08:53 +04:00
{
u8 dir = substream - > stream = = SNDRV_PCM_STREAM_PLAYBACK ? OUT : IN ;
struct snd_pcm_runtime * runtime = substream - > runtime ;
struct fsl_asrc_pair * pair = runtime - > private_data ;
2018-01-29 05:46:46 +03:00
struct device * dev = component - > dev ;
2014-07-29 14:08:53 +04:00
unsigned long flags = DMA_CTRL_ACK ;
/* Prepare and submit Front-End DMA channel */
if ( ! substream - > runtime - > no_period_wakeup )
flags | = DMA_PREP_INTERRUPT ;
pair - > pos = 0 ;
pair - > desc [ ! dir ] = dmaengine_prep_dma_cyclic (
pair - > dma_chan [ ! dir ] , runtime - > dma_addr ,
snd_pcm_lib_buffer_bytes ( substream ) ,
snd_pcm_lib_period_bytes ( substream ) ,
2017-04-20 09:36:07 +03:00
dir = = OUT ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM , flags ) ;
2014-07-29 14:08:53 +04:00
if ( ! pair - > desc [ ! dir ] ) {
dev_err ( dev , " failed to prepare slave DMA for Front-End \n " ) ;
return - ENOMEM ;
}
pair - > desc [ ! dir ] - > callback = fsl_asrc_dma_complete ;
pair - > desc [ ! dir ] - > callback_param = substream ;
dmaengine_submit ( pair - > desc [ ! dir ] ) ;
/* Prepare and submit Back-End DMA channel */
pair - > desc [ dir ] = dmaengine_prep_dma_cyclic (
pair - > dma_chan [ dir ] , 0xffff , 64 , 64 , DMA_DEV_TO_DEV , 0 ) ;
if ( ! pair - > desc [ dir ] ) {
dev_err ( dev , " failed to prepare slave DMA for Back-End \n " ) ;
return - ENOMEM ;
}
dmaengine_submit ( pair - > desc [ dir ] ) ;
return 0 ;
}
2019-10-02 08:34:43 +03:00
static int fsl_asrc_dma_trigger ( struct snd_soc_component * component ,
struct snd_pcm_substream * substream , int cmd )
2014-07-29 14:08:53 +04:00
{
struct snd_pcm_runtime * runtime = substream - > runtime ;
struct fsl_asrc_pair * pair = runtime - > private_data ;
int ret ;
switch ( cmd ) {
case SNDRV_PCM_TRIGGER_START :
case SNDRV_PCM_TRIGGER_RESUME :
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE :
2019-10-02 08:34:43 +03:00
ret = fsl_asrc_dma_prepare_and_submit ( substream , component ) ;
2014-07-29 14:08:53 +04:00
if ( ret )
return ret ;
dma_async_issue_pending ( pair - > dma_chan [ IN ] ) ;
dma_async_issue_pending ( pair - > dma_chan [ OUT ] ) ;
break ;
case SNDRV_PCM_TRIGGER_STOP :
case SNDRV_PCM_TRIGGER_SUSPEND :
case SNDRV_PCM_TRIGGER_PAUSE_PUSH :
2022-06-17 15:01:33 +03:00
dmaengine_terminate_async ( pair - > dma_chan [ OUT ] ) ;
dmaengine_terminate_async ( pair - > dma_chan [ IN ] ) ;
2014-07-29 14:08:53 +04:00
break ;
default :
return - EINVAL ;
}
return 0 ;
}
2019-10-02 08:34:43 +03:00
static int fsl_asrc_dma_hw_params ( struct snd_soc_component * component ,
struct snd_pcm_substream * substream ,
2014-07-29 14:08:53 +04:00
struct snd_pcm_hw_params * params )
{
enum dma_slave_buswidth buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES ;
2022-05-20 06:06:00 +03:00
enum sdma_peripheral_type be_peripheral_type = IMX_DMATYPE_SSI ;
2020-07-20 04:18:38 +03:00
struct snd_soc_pcm_runtime * rtd = asoc_substream_to_rtd ( substream ) ;
2014-07-29 14:08:53 +04:00
bool tx = substream - > stream = = SNDRV_PCM_STREAM_PLAYBACK ;
struct snd_dmaengine_dai_dma_data * dma_params_fe = NULL ;
struct snd_dmaengine_dai_dma_data * dma_params_be = NULL ;
struct snd_pcm_runtime * runtime = substream - > runtime ;
struct fsl_asrc_pair * pair = runtime - > private_data ;
2020-06-12 10:37:50 +03:00
struct dma_chan * tmp_chan = NULL , * be_chan = NULL ;
struct snd_soc_component * component_be = NULL ;
2020-04-16 15:25:31 +03:00
struct fsl_asrc * asrc = pair - > asrc ;
2014-07-29 14:08:53 +04:00
struct dma_slave_config config_fe , config_be ;
2022-05-20 06:06:00 +03:00
struct sdma_peripheral_config audio_config ;
2014-07-29 14:08:53 +04:00
enum asrc_pair_index index = pair - > index ;
2018-01-29 05:46:46 +03:00
struct device * dev = component - > dev ;
2021-03-05 12:19:37 +03:00
struct device_node * of_dma_node ;
2014-07-29 14:08:53 +04:00
int stream = substream - > stream ;
struct imx_dma_data * tmp_data ;
struct snd_soc_dpcm * dpcm ;
struct device * dev_be ;
u8 dir = tx ? OUT : IN ;
dma_cap_mask_t mask ;
2020-04-16 15:25:34 +03:00
int ret , width ;
2014-07-29 14:08:53 +04:00
/* Fetch the Back-End dma_data from DPCM */
2018-09-18 04:31:09 +03:00
for_each_dpcm_be ( rtd , stream , dpcm ) {
2014-07-29 14:08:53 +04:00
struct snd_soc_pcm_runtime * be = dpcm - > be ;
struct snd_pcm_substream * substream_be ;
2020-03-23 08:18:30 +03:00
struct snd_soc_dai * dai = asoc_rtd_to_cpu ( be , 0 ) ;
2014-07-29 14:08:53 +04:00
if ( dpcm - > fe ! = rtd )
continue ;
substream_be = snd_soc_dpcm_get_substream ( be , stream ) ;
dma_params_be = snd_soc_dai_get_dma_data ( dai , substream_be ) ;
dev_be = dai - > dev ;
break ;
}
if ( ! dma_params_be ) {
dev_err ( dev , " failed to get the substream of Back-End \n " ) ;
return - EINVAL ;
}
/* Override dma_data of the Front-End and config its dmaengine */
2020-03-23 08:18:30 +03:00
dma_params_fe = snd_soc_dai_get_dma_data ( asoc_rtd_to_cpu ( rtd , 0 ) , substream ) ;
2020-04-16 15:25:35 +03:00
dma_params_fe - > addr = asrc - > paddr + asrc - > get_fifo_addr ( ! dir , index ) ;
2014-07-29 14:08:53 +04:00
dma_params_fe - > maxburst = dma_params_be - > maxburst ;
2020-04-16 15:25:35 +03:00
pair - > dma_chan [ ! dir ] = asrc - > get_dma_channel ( pair , ! dir ) ;
2014-07-29 14:08:53 +04:00
if ( ! pair - > dma_chan [ ! dir ] ) {
dev_err ( dev , " failed to request DMA channel \n " ) ;
return - EINVAL ;
}
memset ( & config_fe , 0 , sizeof ( config_fe ) ) ;
ret = snd_dmaengine_pcm_prepare_slave_config ( substream , params , & config_fe ) ;
if ( ret ) {
dev_err ( dev , " failed to prepare DMA config for Front-End \n " ) ;
return ret ;
}
ret = dmaengine_slave_config ( pair - > dma_chan [ ! dir ] , & config_fe ) ;
if ( ret ) {
dev_err ( dev , " failed to config DMA channel for Front-End \n " ) ;
return ret ;
}
/* Request and config DMA channel for Back-End */
dma_cap_zero ( mask ) ;
dma_cap_set ( DMA_SLAVE , mask ) ;
dma_cap_set ( DMA_CYCLIC , mask ) ;
2020-06-12 10:37:50 +03:00
/*
* The Back - End device might have already requested a DMA channel ,
* so try to reuse it first , and then request a new one upon NULL .
*/
component_be = snd_soc_lookup_component_nolocked ( dev_be , SND_DMAENGINE_PCM_DRV_NAME ) ;
if ( component_be ) {
be_chan = soc_component_to_pcm ( component_be ) - > chan [ substream - > stream ] ;
tmp_chan = be_chan ;
}
if ( ! tmp_chan )
tmp_chan = dma_request_slave_channel ( dev_be , tx ? " tx " : " rx " ) ;
2019-12-04 15:00:19 +03:00
/*
* An EDMA DEV_TO_DEV channel is fixed and bound with DMA event of each
* peripheral , unlike SDMA channel that is allocated dynamically . So no
2020-06-12 10:37:50 +03:00
* need to configure dma_request and dma_request2 , but get dma_chan of
* Back - End device directly via dma_request_slave_channel .
2019-12-04 15:00:19 +03:00
*/
2020-04-16 15:25:35 +03:00
if ( ! asrc - > use_edma ) {
2019-12-04 15:00:19 +03:00
/* Get DMA request of Back-End */
tmp_data = tmp_chan - > private ;
pair - > dma_data . dma_request = tmp_data - > dma_request ;
2022-05-20 06:06:00 +03:00
be_peripheral_type = tmp_data - > peripheral_type ;
2020-06-12 10:37:50 +03:00
if ( ! be_chan )
dma_release_channel ( tmp_chan ) ;
2019-12-04 15:00:19 +03:00
/* Get DMA request of Front-End */
2020-04-16 15:25:35 +03:00
tmp_chan = asrc - > get_dma_channel ( pair , dir ) ;
2019-12-04 15:00:19 +03:00
tmp_data = tmp_chan - > private ;
pair - > dma_data . dma_request2 = tmp_data - > dma_request ;
pair - > dma_data . peripheral_type = tmp_data - > peripheral_type ;
pair - > dma_data . priority = tmp_data - > priority ;
dma_release_channel ( tmp_chan ) ;
2021-03-05 12:19:37 +03:00
of_dma_node = pair - > dma_chan [ ! dir ] - > device - > dev - > of_node ;
2019-12-04 15:00:19 +03:00
pair - > dma_chan [ dir ] =
2021-03-05 12:19:37 +03:00
__dma_request_channel ( & mask , filter , & pair - > dma_data ,
of_dma_node ) ;
2020-06-12 10:37:51 +03:00
pair - > req_dma_chan = true ;
2019-12-04 15:00:19 +03:00
} else {
2020-06-12 10:37:51 +03:00
pair - > dma_chan [ dir ] = tmp_chan ;
/* Do not flag to release if we are reusing the Back-End one */
pair - > req_dma_chan = ! be_chan ;
2019-12-04 15:00:19 +03:00
}
2014-07-29 14:08:53 +04:00
if ( ! pair - > dma_chan [ dir ] ) {
dev_err ( dev , " failed to request DMA channel for Back-End \n " ) ;
return - EINVAL ;
}
2020-04-16 15:25:34 +03:00
width = snd_pcm_format_physical_width ( asrc - > asrc_format ) ;
if ( width < 8 | | width > 64 )
return - EINVAL ;
else if ( width = = 8 )
buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE ;
else if ( width = = 16 )
2014-07-29 14:08:53 +04:00
buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES ;
2020-04-16 15:25:34 +03:00
else if ( width = = 24 )
buswidth = DMA_SLAVE_BUSWIDTH_3_BYTES ;
else if ( width < = 32 )
2014-07-29 14:08:53 +04:00
buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES ;
2020-04-16 15:25:34 +03:00
else
buswidth = DMA_SLAVE_BUSWIDTH_8_BYTES ;
2014-07-29 14:08:53 +04:00
config_be . direction = DMA_DEV_TO_DEV ;
config_be . src_addr_width = buswidth ;
config_be . src_maxburst = dma_params_be - > maxburst ;
config_be . dst_addr_width = buswidth ;
config_be . dst_maxburst = dma_params_be - > maxburst ;
2022-05-20 06:06:00 +03:00
memset ( & audio_config , 0 , sizeof ( audio_config ) ) ;
config_be . peripheral_config = & audio_config ;
config_be . peripheral_size = sizeof ( audio_config ) ;
if ( tx & & ( be_peripheral_type = = IMX_DMATYPE_SSI_DUAL | |
be_peripheral_type = = IMX_DMATYPE_SPDIF ) )
audio_config . n_fifos_dst = 2 ;
if ( ! tx & & ( be_peripheral_type = = IMX_DMATYPE_SSI_DUAL | |
be_peripheral_type = = IMX_DMATYPE_SPDIF ) )
audio_config . n_fifos_src = 2 ;
2014-07-29 14:08:53 +04:00
if ( tx ) {
2020-04-16 15:25:35 +03:00
config_be . src_addr = asrc - > paddr + asrc - > get_fifo_addr ( OUT , index ) ;
2014-07-29 14:08:53 +04:00
config_be . dst_addr = dma_params_be - > addr ;
} else {
2020-04-16 15:25:35 +03:00
config_be . dst_addr = asrc - > paddr + asrc - > get_fifo_addr ( IN , index ) ;
2014-07-29 14:08:53 +04:00
config_be . src_addr = dma_params_be - > addr ;
}
ret = dmaengine_slave_config ( pair - > dma_chan [ dir ] , & config_be ) ;
if ( ret ) {
dev_err ( dev , " failed to config DMA channel for Back-End \n " ) ;
2020-06-12 10:37:51 +03:00
if ( pair - > req_dma_chan )
dma_release_channel ( pair - > dma_chan [ dir ] ) ;
2014-07-29 14:08:53 +04:00
return ret ;
}
return 0 ;
}
2019-10-02 08:34:43 +03:00
static int fsl_asrc_dma_hw_free ( struct snd_soc_component * component ,
struct snd_pcm_substream * substream )
2014-07-29 14:08:53 +04:00
{
2020-06-12 10:37:51 +03:00
bool tx = substream - > stream = = SNDRV_PCM_STREAM_PLAYBACK ;
2014-07-29 14:08:53 +04:00
struct snd_pcm_runtime * runtime = substream - > runtime ;
struct fsl_asrc_pair * pair = runtime - > private_data ;
2020-06-12 10:37:51 +03:00
u8 dir = tx ? OUT : IN ;
2014-07-29 14:08:53 +04:00
2020-06-12 10:37:51 +03:00
if ( pair - > dma_chan [ ! dir ] )
dma_release_channel ( pair - > dma_chan [ ! dir ] ) ;
2014-07-29 14:08:53 +04:00
2020-06-12 10:37:51 +03:00
/* release dev_to_dev chan if we aren't reusing the Back-End one */
if ( pair - > dma_chan [ dir ] & & pair - > req_dma_chan )
dma_release_channel ( pair - > dma_chan [ dir ] ) ;
2014-07-29 14:08:53 +04:00
2020-06-12 10:37:51 +03:00
pair - > dma_chan [ ! dir ] = NULL ;
pair - > dma_chan [ dir ] = NULL ;
2014-07-29 14:08:53 +04:00
return 0 ;
}
2019-10-02 08:34:43 +03:00
static int fsl_asrc_dma_startup ( struct snd_soc_component * component ,
struct snd_pcm_substream * substream )
2014-07-29 14:08:53 +04:00
{
2019-09-27 04:46:12 +03:00
bool tx = substream - > stream = = SNDRV_PCM_STREAM_PLAYBACK ;
2020-07-20 04:18:38 +03:00
struct snd_soc_pcm_runtime * rtd = asoc_substream_to_rtd ( substream ) ;
2014-07-29 14:08:53 +04:00
struct snd_pcm_runtime * runtime = substream - > runtime ;
2019-09-27 04:46:12 +03:00
struct snd_dmaengine_dai_dma_data * dma_data ;
2018-01-29 05:46:46 +03:00
struct device * dev = component - > dev ;
2020-04-16 15:25:31 +03:00
struct fsl_asrc * asrc = dev_get_drvdata ( dev ) ;
2014-07-29 14:08:53 +04:00
struct fsl_asrc_pair * pair ;
2019-09-27 04:46:12 +03:00
struct dma_chan * tmp_chan = NULL ;
u8 dir = tx ? OUT : IN ;
bool release_pair = true ;
int ret = 0 ;
ret = snd_pcm_hw_constraint_integer ( substream - > runtime ,
SNDRV_PCM_HW_PARAM_PERIODS ) ;
if ( ret < 0 ) {
dev_err ( dev , " failed to set pcm hw params periods \n " ) ;
return ret ;
}
2014-07-29 14:08:53 +04:00
2020-04-16 15:25:35 +03:00
pair = kzalloc ( sizeof ( * pair ) + asrc - > pair_priv_size , GFP_KERNEL ) ;
2017-08-11 16:10:43 +03:00
if ( ! pair )
2014-07-29 14:08:53 +04:00
return - ENOMEM ;
2020-04-16 15:25:31 +03:00
pair - > asrc = asrc ;
2020-04-16 15:25:35 +03:00
pair - > private = ( void * ) pair + sizeof ( struct fsl_asrc_pair ) ;
2014-07-29 14:08:53 +04:00
runtime - > private_data = pair ;
2019-09-27 04:46:12 +03:00
/* Request a dummy pair, which will be released later.
* Request pair function needs channel num as input , for this
* dummy pair , we just request " 1 " channel temporarily .
*/
2020-04-16 15:25:35 +03:00
ret = asrc - > request_pair ( 1 , pair ) ;
2019-09-27 04:46:12 +03:00
if ( ret < 0 ) {
dev_err ( dev , " failed to request asrc pair \n " ) ;
goto req_pair_err ;
}
/* Request a dummy dma channel, which will be released later. */
2020-04-16 15:25:35 +03:00
tmp_chan = asrc - > get_dma_channel ( pair , dir ) ;
2019-09-27 04:46:12 +03:00
if ( ! tmp_chan ) {
dev_err ( dev , " failed to get dma channel \n " ) ;
ret = - EINVAL ;
goto dma_chan_err ;
}
2020-03-23 08:18:30 +03:00
dma_data = snd_soc_dai_get_dma_data ( asoc_rtd_to_cpu ( rtd , 0 ) , substream ) ;
2019-09-27 04:46:12 +03:00
/* Refine the snd_imx_hardware according to caps of DMA. */
ret = snd_dmaengine_pcm_refine_runtime_hwparams ( substream ,
dma_data ,
& snd_imx_hardware ,
tmp_chan ) ;
if ( ret < 0 ) {
dev_err ( dev , " failed to refine runtime hwparams \n " ) ;
goto out ;
}
release_pair = false ;
2014-07-29 14:08:53 +04:00
snd_soc_set_runtime_hwparams ( substream , & snd_imx_hardware ) ;
2019-09-27 04:46:12 +03:00
out :
dma_release_channel ( tmp_chan ) ;
dma_chan_err :
2020-04-16 15:25:35 +03:00
asrc - > release_pair ( pair ) ;
2019-09-27 04:46:12 +03:00
req_pair_err :
if ( release_pair )
kfree ( pair ) ;
return ret ;
2014-07-29 14:08:53 +04:00
}
2019-10-02 08:34:43 +03:00
static int fsl_asrc_dma_shutdown ( struct snd_soc_component * component ,
struct snd_pcm_substream * substream )
2014-07-29 14:08:53 +04:00
{
struct snd_pcm_runtime * runtime = substream - > runtime ;
struct fsl_asrc_pair * pair = runtime - > private_data ;
2020-04-16 15:25:31 +03:00
struct fsl_asrc * asrc ;
2014-08-04 08:19:48 +04:00
if ( ! pair )
return 0 ;
2020-04-16 15:25:31 +03:00
asrc = pair - > asrc ;
2014-07-29 14:08:53 +04:00
2020-04-16 15:25:31 +03:00
if ( asrc - > pair [ pair - > index ] = = pair )
asrc - > pair [ pair - > index ] = NULL ;
2014-07-29 14:08:53 +04:00
kfree ( pair ) ;
return 0 ;
}
2019-10-02 08:34:43 +03:00
static snd_pcm_uframes_t
fsl_asrc_dma_pcm_pointer ( struct snd_soc_component * component ,
struct snd_pcm_substream * substream )
2014-07-29 14:08:53 +04:00
{
struct snd_pcm_runtime * runtime = substream - > runtime ;
struct fsl_asrc_pair * pair = runtime - > private_data ;
return bytes_to_frames ( substream - > runtime , pair - > pos ) ;
}
2019-10-02 08:34:43 +03:00
static int fsl_asrc_dma_pcm_new ( struct snd_soc_component * component ,
struct snd_soc_pcm_runtime * rtd )
2014-07-29 14:08:53 +04:00
{
struct snd_card * card = rtd - > card - > snd_card ;
struct snd_pcm * pcm = rtd - > pcm ;
2021-08-02 10:28:10 +03:00
int ret ;
2014-07-29 14:08:53 +04:00
ret = dma_coerce_mask_and_coherent ( card - > dev , DMA_BIT_MASK ( 32 ) ) ;
if ( ret ) {
dev_err ( card - > dev , " failed to set DMA mask \n " ) ;
return ret ;
}
2021-08-02 10:28:10 +03:00
return snd_pcm_set_fixed_buffer_all ( pcm , SNDRV_DMA_TYPE_DEV ,
card - > dev , FSL_ASRC_DMABUF_SIZE ) ;
2014-07-29 14:08:53 +04:00
}
2018-01-29 05:46:46 +03:00
struct snd_soc_component_driver fsl_asrc_component = {
. name = DRV_NAME ,
2019-10-02 08:34:43 +03:00
. hw_params = fsl_asrc_dma_hw_params ,
. hw_free = fsl_asrc_dma_hw_free ,
. trigger = fsl_asrc_dma_trigger ,
. open = fsl_asrc_dma_startup ,
. close = fsl_asrc_dma_shutdown ,
. pointer = fsl_asrc_dma_pcm_pointer ,
. pcm_construct = fsl_asrc_dma_pcm_new ,
2022-07-04 04:50:17 +03:00
. legacy_dai_naming = 1 ,
2014-07-29 14:08:53 +04:00
} ;
2018-01-29 05:46:46 +03:00
EXPORT_SYMBOL_GPL ( fsl_asrc_component ) ;