2019-05-27 08:55:00 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2010-06-19 16:50:37 +02:00
/*
* Copyright ( C ) 2010 , Lars - Peter Clausen < lars @ metafoo . de >
*/
# include <linux/init.h>
# include <linux/io.h>
2015-02-03 10:55:59 +00:00
# include <linux/of.h>
# include <linux/of_device.h>
2010-06-19 16:50:37 +02:00
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/platform_device.h>
# include <linux/slab.h>
# include <linux/clk.h>
# include <linux/delay.h>
# include <linux/dma-mapping.h>
# include <sound/core.h>
# include <sound/pcm.h>
# include <sound/pcm_params.h>
# include <sound/soc.h>
# include <sound/initval.h>
2013-12-03 18:53:03 +01:00
# include <sound/dmaengine_pcm.h>
2010-06-19 16:50:37 +02:00
# include "jz4740-i2s.h"
# define JZ_REG_AIC_CONF 0x00
# define JZ_REG_AIC_CTRL 0x04
# define JZ_REG_AIC_I2S_FMT 0x10
# define JZ_REG_AIC_FIFO_STATUS 0x14
# define JZ_REG_AIC_I2S_STATUS 0x1c
# define JZ_REG_AIC_CLK_DIV 0x30
# define JZ_REG_AIC_FIFO 0x34
# define JZ_AIC_CONF_FIFO_RX_THRESHOLD_MASK (0xf << 12)
# define JZ_AIC_CONF_FIFO_TX_THRESHOLD_MASK (0xf << 8)
# define JZ_AIC_CONF_OVERFLOW_PLAY_LAST BIT(6)
# define JZ_AIC_CONF_INTERNAL_CODEC BIT(5)
# define JZ_AIC_CONF_I2S BIT(4)
# define JZ_AIC_CONF_RESET BIT(3)
# define JZ_AIC_CONF_BIT_CLK_MASTER BIT(2)
# define JZ_AIC_CONF_SYNC_CLK_MASTER BIT(1)
# define JZ_AIC_CONF_ENABLE BIT(0)
# define JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET 12
# define JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET 8
2020-03-06 23:29:30 +01:00
# define JZ4760_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET 24
# define JZ4760_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET 16
2010-06-19 16:50:37 +02:00
# define JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_MASK (0x7 << 19)
# define JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_MASK (0x7 << 16)
# define JZ_AIC_CTRL_ENABLE_RX_DMA BIT(15)
# define JZ_AIC_CTRL_ENABLE_TX_DMA BIT(14)
# define JZ_AIC_CTRL_MONO_TO_STEREO BIT(11)
# define JZ_AIC_CTRL_SWITCH_ENDIANNESS BIT(10)
# define JZ_AIC_CTRL_SIGNED_TO_UNSIGNED BIT(9)
# define JZ_AIC_CTRL_FLUSH BIT(8)
# define JZ_AIC_CTRL_ENABLE_ROR_INT BIT(6)
# define JZ_AIC_CTRL_ENABLE_TUR_INT BIT(5)
# define JZ_AIC_CTRL_ENABLE_RFS_INT BIT(4)
# define JZ_AIC_CTRL_ENABLE_TFS_INT BIT(3)
# define JZ_AIC_CTRL_ENABLE_LOOPBACK BIT(2)
# define JZ_AIC_CTRL_ENABLE_PLAYBACK BIT(1)
# define JZ_AIC_CTRL_ENABLE_CAPTURE BIT(0)
# define JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_OFFSET 19
# define JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_OFFSET 16
# define JZ_AIC_I2S_FMT_DISABLE_BIT_CLK BIT(12)
2015-03-09 12:11:08 +00:00
# define JZ_AIC_I2S_FMT_DISABLE_BIT_ICLK BIT(13)
2010-06-19 16:50:37 +02:00
# define JZ_AIC_I2S_FMT_ENABLE_SYS_CLK BIT(4)
# define JZ_AIC_I2S_FMT_MSB BIT(0)
# define JZ_AIC_I2S_STATUS_BUSY BIT(2)
# define JZ_AIC_CLK_DIV_MASK 0xf
2020-03-06 23:29:27 +01:00
# define I2SDIV_DV_SHIFT 0
2015-02-03 10:55:57 +00:00
# define I2SDIV_DV_MASK (0xf << I2SDIV_DV_SHIFT)
2015-03-09 12:11:08 +00:00
# define I2SDIV_IDV_SHIFT 8
# define I2SDIV_IDV_MASK (0xf << I2SDIV_IDV_SHIFT)
enum jz47xx_i2s_version {
JZ_I2S_JZ4740 ,
2020-03-06 23:29:30 +01:00
JZ_I2S_JZ4760 ,
2020-03-06 23:29:31 +01:00
JZ_I2S_JZ4770 ,
2015-03-09 12:11:08 +00:00
JZ_I2S_JZ4780 ,
} ;
2010-06-19 16:50:37 +02:00
2020-03-06 23:29:29 +01:00
struct i2s_soc_info {
enum jz47xx_i2s_version version ;
struct snd_soc_dai_driver * dai ;
} ;
2010-06-19 16:50:37 +02:00
struct jz4740_i2s {
struct resource * mem ;
void __iomem * base ;
dma_addr_t phys_base ;
struct clk * clk_aic ;
struct clk * clk_i2s ;
2013-12-03 18:53:03 +01:00
struct snd_dmaengine_dai_dma_data playback_dma_data ;
struct snd_dmaengine_dai_dma_data capture_dma_data ;
2015-03-09 12:11:08 +00:00
2020-03-06 23:29:29 +01:00
const struct i2s_soc_info * soc_info ;
2010-06-19 16:50:37 +02:00
} ;
static inline uint32_t jz4740_i2s_read ( const struct jz4740_i2s * i2s ,
unsigned int reg )
{
return readl ( i2s - > base + reg ) ;
}
static inline void jz4740_i2s_write ( const struct jz4740_i2s * i2s ,
unsigned int reg , uint32_t value )
{
writel ( value , i2s - > base + reg ) ;
}
static int jz4740_i2s_startup ( struct snd_pcm_substream * substream ,
struct snd_soc_dai * dai )
{
2010-03-17 20:15:21 +00:00
struct jz4740_i2s * i2s = snd_soc_dai_get_drvdata ( dai ) ;
2010-06-19 16:50:37 +02:00
uint32_t conf , ctrl ;
2017-07-25 15:44:34 +05:30
int ret ;
2010-06-19 16:50:37 +02:00
2020-05-15 09:47:27 +09:00
if ( snd_soc_dai_active ( dai ) )
2010-06-19 16:50:37 +02:00
return 0 ;
ctrl = jz4740_i2s_read ( i2s , JZ_REG_AIC_CTRL ) ;
ctrl | = JZ_AIC_CTRL_FLUSH ;
jz4740_i2s_write ( i2s , JZ_REG_AIC_CTRL , ctrl ) ;
2017-07-25 15:44:34 +05:30
ret = clk_prepare_enable ( i2s - > clk_i2s ) ;
if ( ret )
return ret ;
2010-06-19 16:50:37 +02:00
conf = jz4740_i2s_read ( i2s , JZ_REG_AIC_CONF ) ;
conf | = JZ_AIC_CONF_ENABLE ;
jz4740_i2s_write ( i2s , JZ_REG_AIC_CONF , conf ) ;
return 0 ;
}
static void jz4740_i2s_shutdown ( struct snd_pcm_substream * substream ,
struct snd_soc_dai * dai )
{
2010-03-17 20:15:21 +00:00
struct jz4740_i2s * i2s = snd_soc_dai_get_drvdata ( dai ) ;
2010-06-19 16:50:37 +02:00
uint32_t conf ;
2020-05-15 09:47:27 +09:00
if ( snd_soc_dai_active ( dai ) )
2010-06-19 16:50:37 +02:00
return ;
conf = jz4740_i2s_read ( i2s , JZ_REG_AIC_CONF ) ;
conf & = ~ JZ_AIC_CONF_ENABLE ;
jz4740_i2s_write ( i2s , JZ_REG_AIC_CONF , conf ) ;
2013-05-12 20:07:39 +02:00
clk_disable_unprepare ( i2s - > clk_i2s ) ;
2010-06-19 16:50:37 +02:00
}
static int jz4740_i2s_trigger ( struct snd_pcm_substream * substream , int cmd ,
struct snd_soc_dai * dai )
{
2010-03-17 20:15:21 +00:00
struct jz4740_i2s * i2s = snd_soc_dai_get_drvdata ( dai ) ;
2010-06-19 16:50:37 +02:00
uint32_t ctrl ;
uint32_t mask ;
if ( substream - > stream = = SNDRV_PCM_STREAM_PLAYBACK )
mask = JZ_AIC_CTRL_ENABLE_PLAYBACK | JZ_AIC_CTRL_ENABLE_TX_DMA ;
else
mask = JZ_AIC_CTRL_ENABLE_CAPTURE | JZ_AIC_CTRL_ENABLE_RX_DMA ;
ctrl = jz4740_i2s_read ( i2s , JZ_REG_AIC_CTRL ) ;
switch ( cmd ) {
case SNDRV_PCM_TRIGGER_START :
case SNDRV_PCM_TRIGGER_RESUME :
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE :
ctrl | = mask ;
break ;
case SNDRV_PCM_TRIGGER_STOP :
case SNDRV_PCM_TRIGGER_SUSPEND :
case SNDRV_PCM_TRIGGER_PAUSE_PUSH :
ctrl & = ~ mask ;
break ;
default :
return - EINVAL ;
}
jz4740_i2s_write ( i2s , JZ_REG_AIC_CTRL , ctrl ) ;
return 0 ;
}
static int jz4740_i2s_set_fmt ( struct snd_soc_dai * dai , unsigned int fmt )
{
2010-03-17 20:15:21 +00:00
struct jz4740_i2s * i2s = snd_soc_dai_get_drvdata ( dai ) ;
2010-06-19 16:50:37 +02:00
uint32_t format = 0 ;
uint32_t conf ;
conf = jz4740_i2s_read ( i2s , JZ_REG_AIC_CONF ) ;
conf & = ~ ( JZ_AIC_CONF_BIT_CLK_MASTER | JZ_AIC_CONF_SYNC_CLK_MASTER ) ;
switch ( fmt & SND_SOC_DAIFMT_MASTER_MASK ) {
case SND_SOC_DAIFMT_CBS_CFS :
conf | = JZ_AIC_CONF_BIT_CLK_MASTER | JZ_AIC_CONF_SYNC_CLK_MASTER ;
format | = JZ_AIC_I2S_FMT_ENABLE_SYS_CLK ;
break ;
case SND_SOC_DAIFMT_CBM_CFS :
conf | = JZ_AIC_CONF_SYNC_CLK_MASTER ;
break ;
case SND_SOC_DAIFMT_CBS_CFM :
conf | = JZ_AIC_CONF_BIT_CLK_MASTER ;
break ;
case SND_SOC_DAIFMT_CBM_CFM :
break ;
default :
return - EINVAL ;
}
switch ( fmt & SND_SOC_DAIFMT_FORMAT_MASK ) {
case SND_SOC_DAIFMT_MSB :
format | = JZ_AIC_I2S_FMT_MSB ;
break ;
case SND_SOC_DAIFMT_I2S :
break ;
default :
return - EINVAL ;
}
switch ( fmt & SND_SOC_DAIFMT_INV_MASK ) {
case SND_SOC_DAIFMT_NB_NF :
break ;
default :
return - EINVAL ;
}
jz4740_i2s_write ( i2s , JZ_REG_AIC_CONF , conf ) ;
jz4740_i2s_write ( i2s , JZ_REG_AIC_I2S_FMT , format ) ;
return 0 ;
}
static int jz4740_i2s_hw_params ( struct snd_pcm_substream * substream ,
struct snd_pcm_hw_params * params , struct snd_soc_dai * dai )
{
2010-03-17 20:15:21 +00:00
struct jz4740_i2s * i2s = snd_soc_dai_get_drvdata ( dai ) ;
2010-06-19 16:50:37 +02:00
unsigned int sample_size ;
2015-02-03 10:55:57 +00:00
uint32_t ctrl , div_reg ;
int div ;
2010-06-19 16:50:37 +02:00
ctrl = jz4740_i2s_read ( i2s , JZ_REG_AIC_CTRL ) ;
2015-02-03 10:55:57 +00:00
div_reg = jz4740_i2s_read ( i2s , JZ_REG_AIC_CLK_DIV ) ;
div = clk_get_rate ( i2s - > clk_i2s ) / ( 64 * params_rate ( params ) ) ;
2010-06-19 16:50:37 +02:00
switch ( params_format ( params ) ) {
case SNDRV_PCM_FORMAT_S8 :
sample_size = 0 ;
break ;
case SNDRV_PCM_FORMAT_S16 :
sample_size = 1 ;
break ;
default :
return - EINVAL ;
}
if ( substream - > stream = = SNDRV_PCM_STREAM_PLAYBACK ) {
ctrl & = ~ JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_MASK ;
ctrl | = sample_size < < JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_OFFSET ;
if ( params_channels ( params ) = = 1 )
ctrl | = JZ_AIC_CTRL_MONO_TO_STEREO ;
else
ctrl & = ~ JZ_AIC_CTRL_MONO_TO_STEREO ;
2015-03-09 12:11:08 +00:00
div_reg & = ~ I2SDIV_DV_MASK ;
div_reg | = ( div - 1 ) < < I2SDIV_DV_SHIFT ;
2010-06-19 16:50:37 +02:00
} else {
ctrl & = ~ JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_MASK ;
ctrl | = sample_size < < JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_OFFSET ;
2015-03-09 12:11:08 +00:00
2020-03-06 23:29:31 +01:00
if ( i2s - > soc_info - > version > = JZ_I2S_JZ4770 ) {
2015-03-09 12:11:08 +00:00
div_reg & = ~ I2SDIV_IDV_MASK ;
div_reg | = ( div - 1 ) < < I2SDIV_IDV_SHIFT ;
} else {
div_reg & = ~ I2SDIV_DV_MASK ;
div_reg | = ( div - 1 ) < < I2SDIV_DV_SHIFT ;
}
2010-06-19 16:50:37 +02:00
}
jz4740_i2s_write ( i2s , JZ_REG_AIC_CTRL , ctrl ) ;
2015-02-03 10:55:57 +00:00
jz4740_i2s_write ( i2s , JZ_REG_AIC_CLK_DIV , div_reg ) ;
2010-06-19 16:50:37 +02:00
return 0 ;
}
static int jz4740_i2s_set_sysclk ( struct snd_soc_dai * dai , int clk_id ,
unsigned int freq , int dir )
{
2010-03-17 20:15:21 +00:00
struct jz4740_i2s * i2s = snd_soc_dai_get_drvdata ( dai ) ;
2010-06-19 16:50:37 +02:00
struct clk * parent ;
int ret = 0 ;
switch ( clk_id ) {
case JZ4740_I2S_CLKSRC_EXT :
parent = clk_get ( NULL , " ext " ) ;
2020-12-03 22:42:27 +08:00
if ( IS_ERR ( parent ) )
return PTR_ERR ( parent ) ;
2010-06-19 16:50:37 +02:00
clk_set_parent ( i2s - > clk_i2s , parent ) ;
break ;
case JZ4740_I2S_CLKSRC_PLL :
parent = clk_get ( NULL , " pll half " ) ;
2020-12-03 22:42:27 +08:00
if ( IS_ERR ( parent ) )
return PTR_ERR ( parent ) ;
2010-06-19 16:50:37 +02:00
clk_set_parent ( i2s - > clk_i2s , parent ) ;
ret = clk_set_rate ( i2s - > clk_i2s , freq ) ;
break ;
default :
return - EINVAL ;
}
clk_put ( parent ) ;
return ret ;
}
2020-01-20 10:03:56 +09:00
static int jz4740_i2s_suspend ( struct snd_soc_component * component )
2010-06-19 16:50:37 +02:00
{
2020-01-20 10:03:56 +09:00
struct jz4740_i2s * i2s = snd_soc_component_get_drvdata ( component ) ;
2010-06-19 16:50:37 +02:00
uint32_t conf ;
2020-05-15 09:47:27 +09:00
if ( snd_soc_component_active ( component ) ) {
2010-06-19 16:50:37 +02:00
conf = jz4740_i2s_read ( i2s , JZ_REG_AIC_CONF ) ;
conf & = ~ JZ_AIC_CONF_ENABLE ;
jz4740_i2s_write ( i2s , JZ_REG_AIC_CONF , conf ) ;
2013-05-12 20:07:39 +02:00
clk_disable_unprepare ( i2s - > clk_i2s ) ;
2010-06-19 16:50:37 +02:00
}
2013-05-12 20:07:39 +02:00
clk_disable_unprepare ( i2s - > clk_aic ) ;
2010-06-19 16:50:37 +02:00
return 0 ;
}
2020-01-20 10:03:56 +09:00
static int jz4740_i2s_resume ( struct snd_soc_component * component )
2010-06-19 16:50:37 +02:00
{
2020-01-20 10:03:56 +09:00
struct jz4740_i2s * i2s = snd_soc_component_get_drvdata ( component ) ;
2010-06-19 16:50:37 +02:00
uint32_t conf ;
2017-07-25 15:44:34 +05:30
int ret ;
2010-06-19 16:50:37 +02:00
2017-07-25 15:44:34 +05:30
ret = clk_prepare_enable ( i2s - > clk_aic ) ;
if ( ret )
return ret ;
2010-06-19 16:50:37 +02:00
2020-05-15 09:47:27 +09:00
if ( snd_soc_component_active ( component ) ) {
2017-07-25 15:44:34 +05:30
ret = clk_prepare_enable ( i2s - > clk_i2s ) ;
if ( ret ) {
clk_disable_unprepare ( i2s - > clk_aic ) ;
return ret ;
}
2010-06-19 16:50:37 +02:00
conf = jz4740_i2s_read ( i2s , JZ_REG_AIC_CONF ) ;
conf | = JZ_AIC_CONF_ENABLE ;
jz4740_i2s_write ( i2s , JZ_REG_AIC_CONF , conf ) ;
}
return 0 ;
}
2010-03-17 20:15:21 +00:00
static void jz4740_i2c_init_pcm_config ( struct jz4740_i2s * i2s )
2010-06-19 16:50:37 +02:00
{
2013-12-03 18:53:03 +01:00
struct snd_dmaengine_dai_dma_data * dma_data ;
2010-03-17 20:15:21 +00:00
/* Playback */
2013-12-03 18:53:03 +01:00
dma_data = & i2s - > playback_dma_data ;
dma_data - > maxburst = 16 ;
dma_data - > addr = i2s - > phys_base + JZ_REG_AIC_FIFO ;
2010-03-17 20:15:21 +00:00
/* Capture */
2013-12-03 18:53:03 +01:00
dma_data = & i2s - > capture_dma_data ;
dma_data - > maxburst = 16 ;
dma_data - > addr = i2s - > phys_base + JZ_REG_AIC_FIFO ;
2010-03-17 20:15:21 +00:00
}
static int jz4740_i2s_dai_probe ( struct snd_soc_dai * dai )
{
struct jz4740_i2s * i2s = snd_soc_dai_get_drvdata ( dai ) ;
2010-06-19 16:50:37 +02:00
uint32_t conf ;
2017-07-25 15:44:34 +05:30
int ret ;
2010-06-19 16:50:37 +02:00
2017-07-25 15:44:34 +05:30
ret = clk_prepare_enable ( i2s - > clk_aic ) ;
if ( ret )
return ret ;
2010-03-17 20:15:21 +00:00
jz4740_i2c_init_pcm_config ( i2s ) ;
2013-12-03 18:53:03 +01:00
snd_soc_dai_init_dma_data ( dai , & i2s - > playback_dma_data ,
& i2s - > capture_dma_data ) ;
2010-03-17 20:15:21 +00:00
2020-03-06 23:29:30 +01:00
if ( i2s - > soc_info - > version > = JZ_I2S_JZ4760 ) {
conf = ( 7 < < JZ4760_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET ) |
( 8 < < JZ4760_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET ) |
2015-03-09 12:11:08 +00:00
JZ_AIC_CONF_OVERFLOW_PLAY_LAST |
JZ_AIC_CONF_I2S |
JZ_AIC_CONF_INTERNAL_CODEC ;
} else {
conf = ( 7 < < JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET ) |
( 8 < < JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET ) |
JZ_AIC_CONF_OVERFLOW_PLAY_LAST |
JZ_AIC_CONF_I2S |
JZ_AIC_CONF_INTERNAL_CODEC ;
}
2010-06-19 16:50:37 +02:00
jz4740_i2s_write ( i2s , JZ_REG_AIC_CONF , JZ_AIC_CONF_RESET ) ;
jz4740_i2s_write ( i2s , JZ_REG_AIC_CONF , conf ) ;
return 0 ;
}
2010-03-17 20:15:21 +00:00
static int jz4740_i2s_dai_remove ( struct snd_soc_dai * dai )
{
struct jz4740_i2s * i2s = snd_soc_dai_get_drvdata ( dai ) ;
2013-05-12 20:07:39 +02:00
clk_disable_unprepare ( i2s - > clk_aic ) ;
2010-03-17 20:15:21 +00:00
return 0 ;
}
2011-11-23 11:40:40 +01:00
static const struct snd_soc_dai_ops jz4740_i2s_dai_ops = {
2010-06-19 16:50:37 +02:00
. startup = jz4740_i2s_startup ,
. shutdown = jz4740_i2s_shutdown ,
. trigger = jz4740_i2s_trigger ,
. hw_params = jz4740_i2s_hw_params ,
. set_fmt = jz4740_i2s_set_fmt ,
. set_sysclk = jz4740_i2s_set_sysclk ,
} ;
# define JZ4740_I2S_FMTS (SNDRV_PCM_FMTBIT_S8 | \
SNDRV_PCM_FMTBIT_S16_LE )
2010-03-17 20:15:21 +00:00
static struct snd_soc_dai_driver jz4740_i2s_dai = {
. probe = jz4740_i2s_dai_probe ,
. remove = jz4740_i2s_dai_remove ,
2010-06-19 16:50:37 +02:00
. playback = {
. channels_min = 1 ,
. channels_max = 2 ,
. rates = SNDRV_PCM_RATE_8000_48000 ,
. formats = JZ4740_I2S_FMTS ,
} ,
. capture = {
. channels_min = 2 ,
. channels_max = 2 ,
. rates = SNDRV_PCM_RATE_8000_48000 ,
. formats = JZ4740_I2S_FMTS ,
} ,
2021-01-15 13:55:20 +09:00
. symmetric_rate = 1 ,
2010-06-19 16:50:37 +02:00
. ops = & jz4740_i2s_dai_ops ,
} ;
2020-03-06 23:29:29 +01:00
static const struct i2s_soc_info jz4740_i2s_soc_info = {
. version = JZ_I2S_JZ4740 ,
. dai = & jz4740_i2s_dai ,
} ;
2020-03-06 23:29:30 +01:00
static const struct i2s_soc_info jz4760_i2s_soc_info = {
. version = JZ_I2S_JZ4760 ,
. dai = & jz4740_i2s_dai ,
} ;
2020-03-06 23:29:31 +01:00
static struct snd_soc_dai_driver jz4770_i2s_dai = {
2015-03-09 12:11:08 +00:00
. probe = jz4740_i2s_dai_probe ,
. remove = jz4740_i2s_dai_remove ,
. playback = {
. channels_min = 1 ,
. channels_max = 2 ,
. rates = SNDRV_PCM_RATE_8000_48000 ,
. formats = JZ4740_I2S_FMTS ,
} ,
. capture = {
. channels_min = 2 ,
. channels_max = 2 ,
. rates = SNDRV_PCM_RATE_8000_48000 ,
. formats = JZ4740_I2S_FMTS ,
} ,
. ops = & jz4740_i2s_dai_ops ,
} ;
2020-03-06 23:29:31 +01:00
static const struct i2s_soc_info jz4770_i2s_soc_info = {
. version = JZ_I2S_JZ4770 ,
. dai = & jz4770_i2s_dai ,
} ;
2020-03-06 23:29:29 +01:00
static const struct i2s_soc_info jz4780_i2s_soc_info = {
. version = JZ_I2S_JZ4780 ,
2020-03-06 23:29:31 +01:00
. dai = & jz4770_i2s_dai ,
2020-03-06 23:29:29 +01:00
} ;
2013-03-21 03:32:28 -07:00
static const struct snd_soc_component_driver jz4740_i2s_component = {
. name = " jz4740-i2s " ,
2020-01-20 10:03:56 +09:00
. suspend = jz4740_i2s_suspend ,
. resume = jz4740_i2s_resume ,
2013-03-21 03:32:28 -07:00
} ;
2015-02-03 10:55:59 +00:00
static const struct of_device_id jz4740_of_matches [ ] = {
2020-03-06 23:29:29 +01:00
{ . compatible = " ingenic,jz4740-i2s " , . data = & jz4740_i2s_soc_info } ,
2020-03-06 23:29:30 +01:00
{ . compatible = " ingenic,jz4760-i2s " , . data = & jz4760_i2s_soc_info } ,
2020-03-06 23:29:31 +01:00
{ . compatible = " ingenic,jz4770-i2s " , . data = & jz4770_i2s_soc_info } ,
2020-03-06 23:29:29 +01:00
{ . compatible = " ingenic,jz4780-i2s " , . data = & jz4780_i2s_soc_info } ,
2015-02-03 10:55:59 +00:00
{ /* sentinel */ }
} ;
2015-09-03 12:58:57 +02:00
MODULE_DEVICE_TABLE ( of , jz4740_of_matches ) ;
2015-02-03 10:55:59 +00:00
2012-12-07 09:26:24 -05:00
static int jz4740_i2s_dev_probe ( struct platform_device * pdev )
2010-06-19 16:50:37 +02:00
{
2020-03-06 23:29:28 +01:00
struct device * dev = & pdev - > dev ;
2010-06-19 16:50:37 +02:00
struct jz4740_i2s * i2s ;
2013-12-03 18:53:02 +01:00
struct resource * mem ;
2010-06-19 16:50:37 +02:00
int ret ;
2020-03-06 23:29:28 +01:00
i2s = devm_kzalloc ( dev , sizeof ( * i2s ) , GFP_KERNEL ) ;
2010-06-19 16:50:37 +02:00
if ( ! i2s )
return - ENOMEM ;
2020-03-06 23:29:29 +01:00
i2s - > soc_info = device_get_match_data ( dev ) ;
2015-03-09 12:11:08 +00:00
2013-12-03 18:53:02 +01:00
mem = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
2020-03-06 23:29:28 +01:00
i2s - > base = devm_ioremap_resource ( dev , mem ) ;
2013-12-03 18:53:02 +01:00
if ( IS_ERR ( i2s - > base ) )
return PTR_ERR ( i2s - > base ) ;
2010-06-19 16:50:37 +02:00
2013-12-03 18:53:02 +01:00
i2s - > phys_base = mem - > start ;
2010-06-19 16:50:37 +02:00
2020-03-06 23:29:28 +01:00
i2s - > clk_aic = devm_clk_get ( dev , " aic " ) ;
2013-12-03 18:53:02 +01:00
if ( IS_ERR ( i2s - > clk_aic ) )
return PTR_ERR ( i2s - > clk_aic ) ;
2010-06-19 16:50:37 +02:00
2020-03-06 23:29:28 +01:00
i2s - > clk_i2s = devm_clk_get ( dev , " i2s " ) ;
2013-12-03 18:53:02 +01:00
if ( IS_ERR ( i2s - > clk_i2s ) )
return PTR_ERR ( i2s - > clk_i2s ) ;
2010-06-19 16:50:37 +02:00
2010-03-17 20:15:21 +00:00
platform_set_drvdata ( pdev , i2s ) ;
2010-06-19 16:50:37 +02:00
2020-03-06 23:29:29 +01:00
ret = devm_snd_soc_register_component ( dev , & jz4740_i2s_component ,
i2s - > soc_info - > dai , 1 ) ;
2013-12-03 18:53:03 +01:00
if ( ret )
return ret ;
2020-03-06 23:29:28 +01:00
return devm_snd_dmaengine_pcm_register ( dev , NULL ,
2013-12-03 18:53:03 +01:00
SND_DMAENGINE_PCM_FLAG_COMPAT ) ;
2010-06-19 16:50:37 +02:00
}
static struct platform_driver jz4740_i2s_driver = {
. probe = jz4740_i2s_dev_probe ,
. driver = {
. name = " jz4740-i2s " ,
2020-05-23 14:54:55 +02:00
. of_match_table = jz4740_of_matches ,
2010-06-19 16:50:37 +02:00
} ,
} ;
2011-11-24 10:13:03 +08:00
module_platform_driver ( jz4740_i2s_driver ) ;
2010-06-19 16:50:37 +02:00
MODULE_AUTHOR ( " Lars-Peter Clausen, <lars@metafoo.de> " ) ;
MODULE_DESCRIPTION ( " Ingenic JZ4740 SoC I2S driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_ALIAS ( " platform:jz4740-i2s " ) ;