2019-05-27 08:55:05 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2012-06-11 18:04:39 +08:00
/*
* linux / sound / soc / pxa / mmp - sspa . c
* Base on pxa2xx - ssp . c
*
* Copyright ( C ) 2011 Marvell International Ltd .
*/
# include <linux/init.h>
# include <linux/module.h>
# include <linux/platform_device.h>
# include <linux/delay.h>
# include <linux/clk.h>
# include <linux/slab.h>
# include <linux/io.h>
2013-08-12 10:42:39 +02:00
# include <linux/dmaengine.h>
2020-05-11 23:01:31 +02:00
# include <linux/pm_runtime.h>
2013-08-12 10:42:39 +02:00
2012-06-11 18:04:39 +08:00
# include <sound/core.h>
# include <sound/pcm.h>
# include <sound/initval.h>
# include <sound/pcm_params.h>
# include <sound/soc.h>
# include <sound/pxa2xx-lib.h>
2013-08-12 10:42:39 +02:00
# include <sound/dmaengine_pcm.h>
2012-06-11 18:04:39 +08:00
# include "mmp-sspa.h"
/*
* SSPA audio private data
*/
struct sspa_priv {
2020-05-11 23:01:34 +02:00
void __iomem * tx_base ;
void __iomem * rx_base ;
2020-05-11 23:01:27 +02:00
struct snd_dmaengine_dai_dma_data playback_dma_data ;
struct snd_dmaengine_dai_dma_data capture_dma_data ;
2020-05-11 23:01:29 +02:00
struct clk * clk ;
2012-06-11 18:04:39 +08:00
struct clk * audio_clk ;
struct clk * sysclk ;
2020-05-11 23:01:34 +02:00
2012-06-11 18:04:39 +08:00
int running_cnt ;
2020-05-11 23:01:31 +02:00
u32 sp ;
u32 ctrl ;
2012-06-11 18:04:39 +08:00
} ;
2020-05-11 23:01:29 +02:00
static void mmp_sspa_tx_enable ( struct sspa_priv * sspa )
2012-06-11 18:04:39 +08:00
{
2020-05-11 23:01:31 +02:00
unsigned int sspa_sp = sspa - > sp ;
2012-06-11 18:04:39 +08:00
2020-05-11 23:01:31 +02:00
sspa_sp & = ~ SSPA_SP_MSL ;
2012-06-11 18:04:39 +08:00
sspa_sp | = SSPA_SP_S_EN ;
sspa_sp | = SSPA_SP_WEN ;
2020-05-11 23:01:34 +02:00
__raw_writel ( sspa_sp , sspa - > tx_base + SSPA_SP ) ;
2012-06-11 18:04:39 +08:00
}
2020-05-11 23:01:29 +02:00
static void mmp_sspa_tx_disable ( struct sspa_priv * sspa )
2012-06-11 18:04:39 +08:00
{
2020-05-11 23:01:31 +02:00
unsigned int sspa_sp = sspa - > sp ;
2012-06-11 18:04:39 +08:00
2020-05-11 23:01:31 +02:00
sspa_sp & = ~ SSPA_SP_MSL ;
2012-06-11 18:04:39 +08:00
sspa_sp & = ~ SSPA_SP_S_EN ;
sspa_sp | = SSPA_SP_WEN ;
2020-05-11 23:01:34 +02:00
__raw_writel ( sspa_sp , sspa - > tx_base + SSPA_SP ) ;
2012-06-11 18:04:39 +08:00
}
2020-05-11 23:01:29 +02:00
static void mmp_sspa_rx_enable ( struct sspa_priv * sspa )
2012-06-11 18:04:39 +08:00
{
2020-05-11 23:01:31 +02:00
unsigned int sspa_sp = sspa - > sp ;
2012-06-11 18:04:39 +08:00
sspa_sp | = SSPA_SP_S_EN ;
sspa_sp | = SSPA_SP_WEN ;
2020-05-11 23:01:34 +02:00
__raw_writel ( sspa_sp , sspa - > rx_base + SSPA_SP ) ;
2012-06-11 18:04:39 +08:00
}
2020-05-11 23:01:29 +02:00
static void mmp_sspa_rx_disable ( struct sspa_priv * sspa )
2012-06-11 18:04:39 +08:00
{
2020-05-11 23:01:31 +02:00
unsigned int sspa_sp = sspa - > sp ;
2012-06-11 18:04:39 +08:00
sspa_sp & = ~ SSPA_SP_S_EN ;
sspa_sp | = SSPA_SP_WEN ;
2020-05-11 23:01:34 +02:00
__raw_writel ( sspa_sp , sspa - > rx_base + SSPA_SP ) ;
2012-06-11 18:04:39 +08:00
}
static int mmp_sspa_startup ( struct snd_pcm_substream * substream ,
struct snd_soc_dai * dai )
{
2020-05-11 23:01:29 +02:00
struct sspa_priv * sspa = snd_soc_dai_get_drvdata ( dai ) ;
2012-06-11 18:04:39 +08:00
2020-05-11 23:01:30 +02:00
clk_prepare_enable ( sspa - > sysclk ) ;
clk_prepare_enable ( sspa - > clk ) ;
2012-06-11 18:04:39 +08:00
return 0 ;
}
static void mmp_sspa_shutdown ( struct snd_pcm_substream * substream ,
struct snd_soc_dai * dai )
{
2020-05-11 23:01:29 +02:00
struct sspa_priv * sspa = snd_soc_dai_get_drvdata ( dai ) ;
2012-06-11 18:04:39 +08:00
2020-05-11 23:01:30 +02:00
clk_disable_unprepare ( sspa - > clk ) ;
clk_disable_unprepare ( sspa - > sysclk ) ;
2012-06-11 18:04:39 +08:00
}
/*
* Set the SSP ports SYSCLK .
*/
static int mmp_sspa_set_dai_sysclk ( struct snd_soc_dai * cpu_dai ,
int clk_id , unsigned int freq , int dir )
{
2020-05-11 23:01:29 +02:00
struct sspa_priv * sspa = snd_soc_dai_get_drvdata ( cpu_dai ) ;
2020-05-11 23:01:34 +02:00
struct device * dev = cpu_dai - > component - > dev ;
2012-06-11 18:04:39 +08:00
int ret = 0 ;
2020-05-11 23:01:34 +02:00
if ( dev - > of_node )
return - ENOTSUPP ;
2012-06-11 18:04:39 +08:00
switch ( clk_id ) {
case MMP_SSPA_CLK_AUDIO :
2020-05-11 23:01:29 +02:00
ret = clk_set_rate ( sspa - > audio_clk , freq ) ;
2012-06-11 18:04:39 +08:00
if ( ret )
return ret ;
break ;
case MMP_SSPA_CLK_PLL :
case MMP_SSPA_CLK_VCXO :
/* not support yet */
return - EINVAL ;
default :
return - EINVAL ;
}
return 0 ;
}
static int mmp_sspa_set_dai_pll ( struct snd_soc_dai * cpu_dai , int pll_id ,
int source , unsigned int freq_in ,
unsigned int freq_out )
{
2020-05-11 23:01:29 +02:00
struct sspa_priv * sspa = snd_soc_dai_get_drvdata ( cpu_dai ) ;
2020-05-11 23:01:34 +02:00
struct device * dev = cpu_dai - > component - > dev ;
2012-06-11 18:04:39 +08:00
int ret = 0 ;
2020-05-11 23:01:34 +02:00
if ( dev - > of_node )
return - ENOTSUPP ;
2012-06-11 18:04:39 +08:00
switch ( pll_id ) {
case MMP_SYSCLK :
2020-05-11 23:01:29 +02:00
ret = clk_set_rate ( sspa - > sysclk , freq_out ) ;
2012-06-11 18:04:39 +08:00
if ( ret )
return ret ;
break ;
case MMP_SSPA_CLK :
2020-05-11 23:01:29 +02:00
ret = clk_set_rate ( sspa - > clk , freq_out ) ;
2012-06-11 18:04:39 +08:00
if ( ret )
return ret ;
break ;
default :
return - ENODEV ;
}
return 0 ;
}
/*
2020-05-11 23:01:31 +02:00
* Set up the sspa dai format .
2012-06-11 18:04:39 +08:00
*/
static int mmp_sspa_set_dai_fmt ( struct snd_soc_dai * cpu_dai ,
unsigned int fmt )
{
2020-05-11 23:01:29 +02:00
struct sspa_priv * sspa = snd_soc_dai_get_drvdata ( cpu_dai ) ;
2012-06-11 18:04:39 +08:00
/* reset port settings */
2020-05-11 23:01:31 +02:00
sspa - > sp = SSPA_SP_WEN | SSPA_SP_S_RST | SSPA_SP_FFLUSH ;
sspa - > ctrl = 0 ;
2012-06-11 18:04:39 +08:00
switch ( fmt & SND_SOC_DAIFMT_MASTER_MASK ) {
case SND_SOC_DAIFMT_CBS_CFS :
2020-05-11 23:01:31 +02:00
sspa - > sp | = SSPA_SP_MSL ;
2012-06-11 18:04:39 +08:00
break ;
case SND_SOC_DAIFMT_CBM_CFM :
break ;
default :
return - EINVAL ;
}
switch ( fmt & SND_SOC_DAIFMT_INV_MASK ) {
case SND_SOC_DAIFMT_NB_NF :
2020-05-11 23:01:31 +02:00
sspa - > sp | = SSPA_SP_FSP ;
2012-06-11 18:04:39 +08:00
break ;
default :
return - EINVAL ;
}
switch ( fmt & SND_SOC_DAIFMT_FORMAT_MASK ) {
case SND_SOC_DAIFMT_I2S :
2020-05-11 23:01:31 +02:00
sspa - > ctrl | = SSPA_CTL_XDATDLY ( 1 ) ;
2012-06-11 18:04:39 +08:00
break ;
default :
return - EINVAL ;
}
/* Since we are configuring the timings for the format by hand
* we have to defer some things until hw_params ( ) where we
* know parameters like the sample size .
*/
return 0 ;
}
/*
* Set the SSPA audio DMA parameters and sample size .
* Can be called multiple times by oss emulation .
*/
static int mmp_sspa_hw_params ( struct snd_pcm_substream * substream ,
struct snd_pcm_hw_params * params ,
struct snd_soc_dai * dai )
{
2020-05-11 23:01:29 +02:00
struct sspa_priv * sspa = snd_soc_dai_get_drvdata ( dai ) ;
2020-05-11 23:01:34 +02:00
struct device * dev = dai - > component - > dev ;
2020-05-11 23:01:31 +02:00
u32 sspa_ctrl = sspa - > ctrl ;
2020-05-11 23:01:32 +02:00
int bits ;
int bitval ;
2012-06-11 18:04:39 +08:00
switch ( params_format ( params ) ) {
case SNDRV_PCM_FORMAT_S8 :
2020-05-11 23:01:32 +02:00
bits = 8 ;
bitval = SSPA_CTL_8_BITS ;
2012-06-11 18:04:39 +08:00
break ;
case SNDRV_PCM_FORMAT_S16_LE :
2020-05-11 23:01:32 +02:00
bits = 16 ;
bitval = SSPA_CTL_16_BITS ;
2012-06-11 18:04:39 +08:00
break ;
case SNDRV_PCM_FORMAT_S24_3LE :
2020-05-11 23:01:32 +02:00
bits = 24 ;
bitval = SSPA_CTL_24_BITS ;
2012-06-11 18:04:39 +08:00
break ;
case SNDRV_PCM_FORMAT_S32_LE :
2020-05-11 23:01:32 +02:00
bits = 32 ;
bitval = SSPA_CTL_32_BITS ;
2012-06-11 18:04:39 +08:00
break ;
default :
return - EINVAL ;
}
2020-11-06 09:59:05 -05:00
sspa_ctrl & = ~ SSPA_CTL_XPH ;
2020-05-11 23:01:34 +02:00
if ( dev - > of_node | | params_channels ( params ) = = 2 )
2020-05-11 23:01:32 +02:00
sspa_ctrl | = SSPA_CTL_XPH ;
sspa_ctrl & = ~ SSPA_CTL_XWDLEN1_MASK ;
sspa_ctrl | = SSPA_CTL_XWDLEN1 ( bitval ) ;
2020-11-18 22:41:06 -05:00
sspa_ctrl & = ~ SSPA_CTL_XWDLEN2_MASK ;
sspa_ctrl | = SSPA_CTL_XWDLEN2 ( bitval ) ;
2020-05-11 23:01:32 +02:00
sspa_ctrl & = ~ SSPA_CTL_XSSZ1_MASK ;
sspa_ctrl | = SSPA_CTL_XSSZ1 ( bitval ) ;
sspa_ctrl & = ~ SSPA_CTL_XSSZ2_MASK ;
sspa_ctrl | = SSPA_CTL_XSSZ2 ( bitval ) ;
sspa - > sp & = ~ SSPA_SP_FWID_MASK ;
sspa - > sp | = SSPA_SP_FWID ( bits - 1 ) ;
sspa - > sp & = ~ SSPA_TXSP_FPER_MASK ;
sspa - > sp | = SSPA_TXSP_FPER ( bits * 2 - 1 ) ;
2020-05-11 23:01:34 +02:00
if ( dev - > of_node ) {
clk_set_rate ( sspa - > clk , params_rate ( params ) *
params_channels ( params ) * bits ) ;
}
2012-06-11 18:04:39 +08:00
if ( substream - > stream = = SNDRV_PCM_STREAM_PLAYBACK ) {
2020-05-11 23:01:34 +02:00
__raw_writel ( sspa_ctrl , sspa - > tx_base + SSPA_CTL ) ;
__raw_writel ( 0x1 , sspa - > tx_base + SSPA_FIFO_UL ) ;
2012-06-11 18:04:39 +08:00
} else {
2020-05-11 23:01:34 +02:00
__raw_writel ( sspa_ctrl , sspa - > rx_base + SSPA_CTL ) ;
__raw_writel ( 0x0 , sspa - > rx_base + SSPA_FIFO_UL ) ;
2012-06-11 18:04:39 +08:00
}
return 0 ;
}
static int mmp_sspa_trigger ( struct snd_pcm_substream * substream , int cmd ,
struct snd_soc_dai * dai )
{
2020-05-11 23:01:29 +02:00
struct sspa_priv * sspa = snd_soc_dai_get_drvdata ( dai ) ;
2012-06-11 18:04:39 +08:00
int ret = 0 ;
switch ( cmd ) {
case SNDRV_PCM_TRIGGER_START :
case SNDRV_PCM_TRIGGER_RESUME :
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE :
/*
* whatever playback or capture , must enable rx .
* this is a hw issue , so need check if rx has been
* enabled or not ; if has been enabled by another
* stream , do not enable again .
*/
2020-05-11 23:01:29 +02:00
if ( ! sspa - > running_cnt )
2012-06-11 18:04:39 +08:00
mmp_sspa_rx_enable ( sspa ) ;
if ( substream - > stream = = SNDRV_PCM_STREAM_PLAYBACK )
mmp_sspa_tx_enable ( sspa ) ;
2020-05-11 23:01:29 +02:00
sspa - > running_cnt + + ;
2012-06-11 18:04:39 +08:00
break ;
case SNDRV_PCM_TRIGGER_STOP :
case SNDRV_PCM_TRIGGER_SUSPEND :
case SNDRV_PCM_TRIGGER_PAUSE_PUSH :
2020-05-11 23:01:29 +02:00
sspa - > running_cnt - - ;
2012-06-11 18:04:39 +08:00
if ( substream - > stream = = SNDRV_PCM_STREAM_PLAYBACK )
mmp_sspa_tx_disable ( sspa ) ;
/* have no capture stream, disable rx port */
2020-05-11 23:01:29 +02:00
if ( ! sspa - > running_cnt )
2012-06-11 18:04:39 +08:00
mmp_sspa_rx_disable ( sspa ) ;
break ;
default :
ret = - EINVAL ;
}
return ret ;
}
static int mmp_sspa_probe ( struct snd_soc_dai * dai )
{
2020-05-11 23:01:29 +02:00
struct sspa_priv * sspa = dev_get_drvdata ( dai - > dev ) ;
2012-06-11 18:04:39 +08:00
2020-05-11 23:01:27 +02:00
snd_soc_dai_init_dma_data ( dai ,
2020-05-11 23:01:29 +02:00
& sspa - > playback_dma_data ,
& sspa - > capture_dma_data ) ;
2020-05-11 23:01:27 +02:00
2012-06-11 18:04:39 +08:00
return 0 ;
}
# define MMP_SSPA_RATES SNDRV_PCM_RATE_8000_192000
# define MMP_SSPA_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
SNDRV_PCM_FMTBIT_S16_LE | \
2020-05-11 23:01:24 +02:00
SNDRV_PCM_FMTBIT_S24_3LE | \
2012-06-11 18:04:39 +08:00
SNDRV_PCM_FMTBIT_S32_LE )
2017-07-13 01:05:08 -05:00
static const struct snd_soc_dai_ops mmp_sspa_dai_ops = {
2012-06-11 18:04:39 +08:00
. startup = mmp_sspa_startup ,
. shutdown = mmp_sspa_shutdown ,
. trigger = mmp_sspa_trigger ,
. hw_params = mmp_sspa_hw_params ,
. set_sysclk = mmp_sspa_set_dai_sysclk ,
. set_pll = mmp_sspa_set_dai_pll ,
. set_fmt = mmp_sspa_set_dai_fmt ,
} ;
2013-05-14 22:19:52 +02:00
static struct snd_soc_dai_driver mmp_sspa_dai = {
2012-06-11 18:04:39 +08:00
. probe = mmp_sspa_probe ,
. playback = {
. channels_min = 1 ,
. channels_max = 128 ,
. rates = MMP_SSPA_RATES ,
. formats = MMP_SSPA_FORMATS ,
} ,
. capture = {
. channels_min = 1 ,
. channels_max = 2 ,
. rates = MMP_SSPA_RATES ,
. formats = MMP_SSPA_FORMATS ,
} ,
. ops = & mmp_sspa_dai_ops ,
} ;
2020-05-11 23:01:28 +02:00
# define MMP_PCM_INFO (SNDRV_PCM_INFO_MMAP | \
SNDRV_PCM_INFO_MMAP_VALID | \
SNDRV_PCM_INFO_INTERLEAVED | \
SNDRV_PCM_INFO_PAUSE | \
SNDRV_PCM_INFO_RESUME | \
SNDRV_PCM_INFO_NO_PERIOD_WAKEUP )
static const struct snd_pcm_hardware mmp_pcm_hardware [ ] = {
{
. info = MMP_PCM_INFO ,
. period_bytes_min = 1024 ,
. period_bytes_max = 2048 ,
. periods_min = 2 ,
. periods_max = 32 ,
. buffer_bytes_max = 4096 ,
. fifo_size = 32 ,
} ,
{
. info = MMP_PCM_INFO ,
. period_bytes_min = 1024 ,
. period_bytes_max = 2048 ,
. periods_min = 2 ,
. periods_max = 32 ,
. buffer_bytes_max = 4096 ,
. fifo_size = 32 ,
} ,
} ;
static const struct snd_dmaengine_pcm_config mmp_pcm_config = {
. prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config ,
. pcm_hardware = mmp_pcm_hardware ,
. prealloc_buffer_size = 4096 ,
} ;
static int mmp_pcm_mmap ( struct snd_soc_component * component ,
struct snd_pcm_substream * substream ,
struct vm_area_struct * vma )
{
vma - > vm_flags | = VM_DONTEXPAND | VM_DONTDUMP ;
vma - > vm_page_prot = pgprot_noncached ( vma - > vm_page_prot ) ;
return remap_pfn_range ( vma , vma - > vm_start ,
substream - > dma_buffer . addr > > PAGE_SHIFT ,
vma - > vm_end - vma - > vm_start , vma - > vm_page_prot ) ;
}
2020-05-11 23:01:31 +02:00
static int mmp_sspa_open ( struct snd_soc_component * component ,
struct snd_pcm_substream * substream )
{
struct sspa_priv * sspa = snd_soc_component_get_drvdata ( component ) ;
pm_runtime_get_sync ( component - > dev ) ;
/* we can only change the settings if the port is not in use */
2020-05-11 23:01:34 +02:00
if ( ( __raw_readl ( sspa - > tx_base + SSPA_SP ) & SSPA_SP_S_EN ) | |
( __raw_readl ( sspa - > rx_base + SSPA_SP ) & SSPA_SP_S_EN ) ) {
2020-05-11 23:01:31 +02:00
dev_err ( component - > dev ,
" can't change hardware dai format: stream is in use \n " ) ;
return - EBUSY ;
}
2020-05-11 23:01:34 +02:00
__raw_writel ( sspa - > sp , sspa - > tx_base + SSPA_SP ) ;
__raw_writel ( sspa - > sp , sspa - > rx_base + SSPA_SP ) ;
2020-05-11 23:01:31 +02:00
sspa - > sp & = ~ ( SSPA_SP_S_RST | SSPA_SP_FFLUSH ) ;
2020-05-11 23:01:34 +02:00
__raw_writel ( sspa - > sp , sspa - > tx_base + SSPA_SP ) ;
__raw_writel ( sspa - > sp , sspa - > rx_base + SSPA_SP ) ;
2020-05-11 23:01:31 +02:00
/*
* FIXME : hw issue , for the tx serial port ,
* can not config the master / slave mode ;
* so must clean this bit .
* The master / slave mode has been set in the
* rx port .
*/
2020-05-11 23:01:34 +02:00
__raw_writel ( sspa - > sp & ~ SSPA_SP_MSL , sspa - > tx_base + SSPA_SP ) ;
2020-05-11 23:01:31 +02:00
2020-05-11 23:01:34 +02:00
__raw_writel ( sspa - > ctrl , sspa - > tx_base + SSPA_CTL ) ;
__raw_writel ( sspa - > ctrl , sspa - > rx_base + SSPA_CTL ) ;
2020-05-11 23:01:31 +02:00
return 0 ;
}
static int mmp_sspa_close ( struct snd_soc_component * component ,
struct snd_pcm_substream * substream )
{
pm_runtime_put_sync ( component - > dev ) ;
return 0 ;
}
2013-03-21 03:34:48 -07:00
static const struct snd_soc_component_driver mmp_sspa_component = {
. name = " mmp-sspa " ,
2020-05-11 23:01:28 +02:00
. mmap = mmp_pcm_mmap ,
2020-05-11 23:01:31 +02:00
. open = mmp_sspa_open ,
. close = mmp_sspa_close ,
2013-03-21 03:34:48 -07:00
} ;
2012-12-07 09:26:17 -05:00
static int asoc_mmp_sspa_probe ( struct platform_device * pdev )
2012-06-11 18:04:39 +08:00
{
2020-05-11 23:01:29 +02:00
struct sspa_priv * sspa ;
2020-05-20 10:35:16 +02:00
int ret ;
2012-06-11 18:04:39 +08:00
2020-05-11 23:01:29 +02:00
sspa = devm_kzalloc ( & pdev - > dev ,
2012-06-11 18:04:39 +08:00
sizeof ( struct sspa_priv ) , GFP_KERNEL ) ;
2020-05-11 23:01:29 +02:00
if ( ! sspa )
2012-06-11 18:04:39 +08:00
return - ENOMEM ;
2020-05-11 23:01:34 +02:00
if ( pdev - > dev . of_node ) {
sspa - > rx_base = devm_platform_ioremap_resource ( pdev , 0 ) ;
if ( IS_ERR ( sspa - > rx_base ) )
return PTR_ERR ( sspa - > rx_base ) ;
2012-06-11 18:04:39 +08:00
2020-05-11 23:01:34 +02:00
sspa - > tx_base = devm_platform_ioremap_resource ( pdev , 1 ) ;
if ( IS_ERR ( sspa - > tx_base ) )
return PTR_ERR ( sspa - > tx_base ) ;
2012-06-11 18:04:39 +08:00
2020-05-11 23:01:34 +02:00
sspa - > clk = devm_clk_get ( & pdev - > dev , " bitclk " ) ;
if ( IS_ERR ( sspa - > clk ) )
return PTR_ERR ( sspa - > clk ) ;
2012-06-11 18:04:39 +08:00
2020-05-11 23:01:34 +02:00
sspa - > audio_clk = devm_clk_get ( & pdev - > dev , " audio " ) ;
if ( IS_ERR ( sspa - > audio_clk ) )
return PTR_ERR ( sspa - > audio_clk ) ;
} else {
struct resource * res ;
res = platform_get_resource ( pdev , IORESOURCE_IO , 0 ) ;
if ( res = = NULL )
return - ENODEV ;
sspa - > rx_base = devm_ioremap ( & pdev - > dev , res - > start , 0x30 ) ;
2020-05-27 03:02:10 +00:00
if ( ! sspa - > rx_base )
return - ENOMEM ;
2020-05-11 23:01:34 +02:00
sspa - > tx_base = devm_ioremap ( & pdev - > dev ,
res - > start + 0x80 , 0x30 ) ;
2020-05-27 03:02:10 +00:00
if ( ! sspa - > tx_base )
return - ENOMEM ;
2020-05-11 23:01:34 +02:00
sspa - > clk = devm_clk_get ( & pdev - > dev , NULL ) ;
if ( IS_ERR ( sspa - > clk ) )
return PTR_ERR ( sspa - > clk ) ;
sspa - > audio_clk = clk_get ( NULL , " mmp-audio " ) ;
if ( IS_ERR ( sspa - > audio_clk ) )
return PTR_ERR ( sspa - > audio_clk ) ;
sspa - > sysclk = clk_get ( NULL , " mmp-sysclk " ) ;
if ( IS_ERR ( sspa - > sysclk ) ) {
clk_put ( sspa - > audio_clk ) ;
return PTR_ERR ( sspa - > sysclk ) ;
}
2012-06-11 18:04:39 +08:00
}
2020-05-11 23:01:29 +02:00
platform_set_drvdata ( pdev , sspa ) ;
2012-06-11 18:04:39 +08:00
2020-05-11 23:01:29 +02:00
sspa - > playback_dma_data . maxburst = 4 ;
sspa - > capture_dma_data . maxburst = 4 ;
2020-05-11 23:01:27 +02:00
/* You know, these addresses are actually ignored. */
2020-05-11 23:01:34 +02:00
sspa - > capture_dma_data . addr = SSPA_D ;
sspa - > playback_dma_data . addr = 0x80 + SSPA_D ;
2020-05-11 23:01:27 +02:00
2020-05-11 23:01:28 +02:00
if ( pdev - > dev . of_node ) {
ret = devm_snd_dmaengine_pcm_register ( & pdev - > dev ,
& mmp_pcm_config , 0 ) ;
if ( ret )
return ret ;
}
2020-05-20 10:35:16 +02:00
ret = devm_snd_soc_register_component ( & pdev - > dev , & mmp_sspa_component ,
& mmp_sspa_dai , 1 ) ;
if ( ret )
return ret ;
pm_runtime_enable ( & pdev - > dev ) ;
clk_prepare_enable ( sspa - > audio_clk ) ;
return 0 ;
2012-06-11 18:04:39 +08:00
}
2012-12-07 09:26:17 -05:00
static int asoc_mmp_sspa_remove ( struct platform_device * pdev )
2012-06-11 18:04:39 +08:00
{
2020-05-11 23:01:29 +02:00
struct sspa_priv * sspa = platform_get_drvdata ( pdev ) ;
2012-06-11 18:04:39 +08:00
2020-05-11 23:01:30 +02:00
clk_disable_unprepare ( sspa - > audio_clk ) ;
2020-05-11 23:01:31 +02:00
pm_runtime_disable ( & pdev - > dev ) ;
2020-05-11 23:01:34 +02:00
if ( pdev - > dev . of_node )
return 0 ;
2020-05-11 23:01:29 +02:00
clk_put ( sspa - > audio_clk ) ;
clk_put ( sspa - > sysclk ) ;
2012-06-11 18:04:39 +08:00
return 0 ;
}
2020-05-11 23:01:34 +02:00
# ifdef CONFIG_OF
static const struct of_device_id mmp_sspa_of_match [ ] = {
{ . compatible = " marvell,mmp-sspa " } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , mmp_sspa_of_match ) ;
# endif
2012-06-11 18:04:39 +08:00
static struct platform_driver asoc_mmp_sspa_driver = {
. driver = {
. name = " mmp-sspa-dai " ,
2020-05-11 23:01:34 +02:00
. of_match_table = of_match_ptr ( mmp_sspa_of_match ) ,
2012-06-11 18:04:39 +08:00
} ,
. probe = asoc_mmp_sspa_probe ,
2012-12-07 09:26:17 -05:00
. remove = asoc_mmp_sspa_remove ,
2012-06-11 18:04:39 +08:00
} ;
module_platform_driver ( asoc_mmp_sspa_driver ) ;
MODULE_AUTHOR ( " Leo Yan <leoy@marvell.com> " ) ;
MODULE_DESCRIPTION ( " MMP SSPA SoC Interface " ) ;
MODULE_LICENSE ( " GPL " ) ;
2016-05-06 17:27:34 +02:00
MODULE_ALIAS ( " platform:mmp-sspa-dai " ) ;