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 >
*/
2022-10-23 15:33:23 +01:00
# include <linux/bitfield.h>
2022-10-23 15:33:24 +01:00
# include <linux/clk.h>
# include <linux/delay.h>
# include <linux/dma-mapping.h>
2010-06-19 16:50:37 +02:00
# include <linux/init.h>
# include <linux/io.h>
# include <linux/kernel.h>
# include <linux/module.h>
2022-07-06 22:13:20 +01:00
# include <linux/mod_devicetable.h>
2010-06-19 16:50:37 +02:00
# include <linux/platform_device.h>
2022-10-23 15:33:21 +01:00
# include <linux/regmap.h>
2010-06-19 16:50:37 +02:00
# include <linux/slab.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
# 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
2022-10-23 15:33:24 +01:00
# 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_CTRL_OUTPUT_SAMPLE_SIZE GENMASK(21, 19)
# define JZ_AIC_CTRL_INPUT_SAMPLE_SIZE GENMASK(18, 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)
2022-10-23 15:33:20 +01:00
# define JZ_AIC_CTRL_TFLUSH BIT(8)
# define JZ_AIC_CTRL_RFLUSH BIT(7)
2022-10-23 15:33:24 +01:00
# 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_I2S_FMT_DISABLE_BIT_CLK BIT(12)
# define JZ_AIC_I2S_FMT_DISABLE_BIT_ICLK BIT(13)
# 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)
2010-06-19 16:50:37 +02:00
2020-03-06 23:29:29 +01:00
struct i2s_soc_info {
struct snd_soc_dai_driver * dai ;
2022-10-23 15:33:20 +01:00
2022-10-23 15:33:22 +01:00
struct reg_field field_rx_fifo_thresh ;
struct reg_field field_tx_fifo_thresh ;
struct reg_field field_i2sdiv_capture ;
struct reg_field field_i2sdiv_playback ;
2022-10-23 15:33:20 +01:00
bool shared_fifo_flush ;
2020-03-06 23:29:29 +01:00
} ;
2010-06-19 16:50:37 +02:00
struct jz4740_i2s {
2022-10-23 15:33:21 +01:00
struct regmap * regmap ;
2010-06-19 16:50:37 +02:00
2022-10-23 15:33:22 +01:00
struct regmap_field * field_rx_fifo_thresh ;
struct regmap_field * field_tx_fifo_thresh ;
struct regmap_field * field_i2sdiv_capture ;
struct regmap_field * field_i2sdiv_playback ;
2010-06-19 16:50:37 +02:00
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 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 ) ;
2017-07-25 15:44:34 +05:30
int ret ;
2010-06-19 16:50:37 +02:00
2022-10-23 15:33:20 +01:00
/*
* When we can flush FIFOs independently , only flush the FIFO
* that is starting up . We can do this when the DAI is active
* because it does not disturb other active substreams .
*/
if ( ! i2s - > soc_info - > shared_fifo_flush ) {
if ( substream - > stream = = SNDRV_PCM_STREAM_PLAYBACK )
2022-10-23 15:33:21 +01:00
regmap_set_bits ( i2s - > regmap , JZ_REG_AIC_CTRL , JZ_AIC_CTRL_TFLUSH ) ;
2022-10-23 15:33:20 +01:00
else
2022-10-23 15:33:21 +01:00
regmap_set_bits ( i2s - > regmap , JZ_REG_AIC_CTRL , JZ_AIC_CTRL_RFLUSH ) ;
2022-10-23 15:33:20 +01: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 ;
2022-10-23 15:33:20 +01:00
/*
* When there is a shared flush bit for both FIFOs , the TFLUSH
* bit flushes both FIFOs . Flushing while the DAI is active would
* cause FIFO underruns in other active substreams so we have to
* guard this behind the snd_soc_dai_active ( ) check .
*/
if ( i2s - > soc_info - > shared_fifo_flush )
2022-10-23 15:33:21 +01:00
regmap_set_bits ( i2s - > regmap , JZ_REG_AIC_CTRL , JZ_AIC_CTRL_TFLUSH ) ;
2010-06-19 16:50:37 +02:00
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
2022-10-23 15:33:21 +01:00
regmap_set_bits ( i2s - > regmap , JZ_REG_AIC_CONF , JZ_AIC_CONF_ENABLE ) ;
2010-06-19 16:50:37 +02:00
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
2020-05-15 09:47:27 +09:00
if ( snd_soc_dai_active ( dai ) )
2010-06-19 16:50:37 +02:00
return ;
2022-10-23 15:33:21 +01:00
regmap_clear_bits ( i2s - > regmap , JZ_REG_AIC_CONF , JZ_AIC_CONF_ENABLE ) ;
2010-06-19 16:50:37 +02:00
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 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 ;
switch ( cmd ) {
case SNDRV_PCM_TRIGGER_START :
case SNDRV_PCM_TRIGGER_RESUME :
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE :
2022-10-23 15:33:21 +01:00
regmap_set_bits ( i2s - > regmap , JZ_REG_AIC_CTRL , mask ) ;
2010-06-19 16:50:37 +02:00
break ;
case SNDRV_PCM_TRIGGER_STOP :
case SNDRV_PCM_TRIGGER_SUSPEND :
case SNDRV_PCM_TRIGGER_PAUSE_PUSH :
2022-10-23 15:33:21 +01:00
regmap_clear_bits ( i2s - > regmap , JZ_REG_AIC_CTRL , mask ) ;
2010-06-19 16:50:37 +02:00
break ;
default :
return - EINVAL ;
}
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 ) ;
2022-10-23 15:33:21 +01:00
const unsigned int conf_mask = JZ_AIC_CONF_BIT_CLK_MASTER |
JZ_AIC_CONF_SYNC_CLK_MASTER ;
unsigned int conf = 0 , format = 0 ;
2010-06-19 16:50:37 +02:00
2022-05-19 16:42:34 +01:00
switch ( fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK ) {
case SND_SOC_DAIFMT_BP_FP :
2010-06-19 16:50:37 +02:00
conf | = JZ_AIC_CONF_BIT_CLK_MASTER | JZ_AIC_CONF_SYNC_CLK_MASTER ;
format | = JZ_AIC_I2S_FMT_ENABLE_SYS_CLK ;
break ;
2022-05-19 16:42:34 +01:00
case SND_SOC_DAIFMT_BC_FP :
2010-06-19 16:50:37 +02:00
conf | = JZ_AIC_CONF_SYNC_CLK_MASTER ;
break ;
2022-05-19 16:42:34 +01:00
case SND_SOC_DAIFMT_BP_FC :
2010-06-19 16:50:37 +02:00
conf | = JZ_AIC_CONF_BIT_CLK_MASTER ;
break ;
2022-05-19 16:42:34 +01:00
case SND_SOC_DAIFMT_BC_FC :
2010-06-19 16:50:37 +02:00
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 ;
}
2022-10-23 15:33:21 +01:00
regmap_update_bits ( i2s - > regmap , JZ_REG_AIC_CONF , conf_mask , conf ) ;
regmap_write ( i2s - > regmap , JZ_REG_AIC_I2S_FMT , format ) ;
2010-06-19 16:50:37 +02:00
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 ) ;
2022-10-23 15:33:22 +01:00
struct regmap_field * div_field ;
2010-06-19 16:50:37 +02:00
unsigned int sample_size ;
2022-10-23 15:33:22 +01:00
uint32_t ctrl ;
2015-02-03 10:55:57 +00:00
int div ;
2010-06-19 16:50:37 +02:00
2022-10-23 15:33:21 +01:00
regmap_read ( i2s - > regmap , JZ_REG_AIC_CTRL , & ctrl ) ;
2010-06-19 16:50:37 +02:00
2015-02-03 10:55:57 +00:00
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 ;
2022-10-23 15:33:25 +01:00
case SNDRV_PCM_FORMAT_S16_LE :
2010-06-19 16:50:37 +02:00
sample_size = 1 ;
break ;
2022-10-23 15:33:25 +01:00
case SNDRV_PCM_FORMAT_S20_LE :
sample_size = 3 ;
break ;
case SNDRV_PCM_FORMAT_S24_LE :
sample_size = 4 ;
break ;
2010-06-19 16:50:37 +02:00
default :
return - EINVAL ;
}
if ( substream - > stream = = SNDRV_PCM_STREAM_PLAYBACK ) {
2022-10-23 15:33:23 +01:00
ctrl & = ~ JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE ;
ctrl | = FIELD_PREP ( JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE , sample_size ) ;
2010-06-19 16:50:37 +02:00
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
2022-10-23 15:33:22 +01:00
div_field = i2s - > field_i2sdiv_playback ;
2010-06-19 16:50:37 +02:00
} else {
2022-10-23 15:33:23 +01:00
ctrl & = ~ JZ_AIC_CTRL_INPUT_SAMPLE_SIZE ;
ctrl | = FIELD_PREP ( JZ_AIC_CTRL_INPUT_SAMPLE_SIZE , sample_size ) ;
2015-03-09 12:11:08 +00:00
2022-10-23 15:33:22 +01:00
div_field = i2s - > field_i2sdiv_capture ;
2010-06-19 16:50:37 +02:00
}
2022-10-23 15:33:21 +01:00
regmap_write ( i2s - > regmap , JZ_REG_AIC_CTRL , ctrl ) ;
2022-10-23 15:33:22 +01:00
regmap_field_write ( div_field , div - 1 ) ;
2010-06-19 16:50:37 +02:00
return 0 ;
}
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 ) ;
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
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 ,
2022-05-19 16:43:01 +01:00
. set_fmt = jz4740_i2s_set_fmt ,
2010-06-19 16:50:37 +02:00
} ;
# define JZ4740_I2S_FMTS (SNDRV_PCM_FMTBIT_S8 | \
2022-10-23 15:33:25 +01:00
SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S20_LE | \
SNDRV_PCM_FMTBIT_S24_LE )
2010-06-19 16:50:37 +02:00
2010-03-17 20:15:21 +00:00
static struct snd_soc_dai_driver jz4740_i2s_dai = {
. probe = jz4740_i2s_dai_probe ,
2010-06-19 16:50:37 +02:00
. playback = {
. channels_min = 1 ,
. channels_max = 2 ,
2022-10-23 15:33:26 +01:00
. rates = SNDRV_PCM_RATE_CONTINUOUS ,
2010-06-19 16:50:37 +02:00
. formats = JZ4740_I2S_FMTS ,
} ,
. capture = {
. channels_min = 2 ,
. channels_max = 2 ,
2022-10-23 15:33:26 +01:00
. rates = SNDRV_PCM_RATE_CONTINUOUS ,
2010-06-19 16:50:37 +02:00
. 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 = {
2022-10-23 15:33:22 +01:00
. dai = & jz4740_i2s_dai ,
. field_rx_fifo_thresh = REG_FIELD ( JZ_REG_AIC_CONF , 12 , 15 ) ,
. field_tx_fifo_thresh = REG_FIELD ( JZ_REG_AIC_CONF , 8 , 11 ) ,
. field_i2sdiv_capture = REG_FIELD ( JZ_REG_AIC_CLK_DIV , 0 , 3 ) ,
. field_i2sdiv_playback = REG_FIELD ( JZ_REG_AIC_CLK_DIV , 0 , 3 ) ,
. shared_fifo_flush = true ,
2020-03-06 23:29:29 +01:00
} ;
2020-03-06 23:29:30 +01:00
static const struct i2s_soc_info jz4760_i2s_soc_info = {
2022-10-23 15:33:22 +01:00
. dai = & jz4740_i2s_dai ,
. field_rx_fifo_thresh = REG_FIELD ( JZ_REG_AIC_CONF , 24 , 27 ) ,
. field_tx_fifo_thresh = REG_FIELD ( JZ_REG_AIC_CONF , 16 , 20 ) ,
. field_i2sdiv_capture = REG_FIELD ( JZ_REG_AIC_CLK_DIV , 0 , 3 ) ,
. field_i2sdiv_playback = REG_FIELD ( JZ_REG_AIC_CLK_DIV , 0 , 3 ) ,
2020-03-06 23:29:30 +01:00
} ;
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 ,
. playback = {
. channels_min = 1 ,
. channels_max = 2 ,
2022-10-23 15:33:26 +01:00
. rates = SNDRV_PCM_RATE_CONTINUOUS ,
2015-03-09 12:11:08 +00:00
. formats = JZ4740_I2S_FMTS ,
} ,
. capture = {
. channels_min = 2 ,
. channels_max = 2 ,
2022-10-23 15:33:26 +01:00
. rates = SNDRV_PCM_RATE_CONTINUOUS ,
2015-03-09 12:11:08 +00:00
. 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 = {
2022-10-23 15:33:22 +01:00
. dai = & jz4770_i2s_dai ,
. field_rx_fifo_thresh = REG_FIELD ( JZ_REG_AIC_CONF , 24 , 27 ) ,
. field_tx_fifo_thresh = REG_FIELD ( JZ_REG_AIC_CONF , 16 , 20 ) ,
. field_i2sdiv_capture = REG_FIELD ( JZ_REG_AIC_CLK_DIV , 8 , 11 ) ,
. field_i2sdiv_playback = REG_FIELD ( JZ_REG_AIC_CLK_DIV , 0 , 3 ) ,
2020-03-06 23:29:31 +01:00
} ;
2020-03-06 23:29:29 +01:00
static const struct i2s_soc_info jz4780_i2s_soc_info = {
2022-10-23 15:33:22 +01:00
. dai = & jz4770_i2s_dai ,
. field_rx_fifo_thresh = REG_FIELD ( JZ_REG_AIC_CONF , 24 , 27 ) ,
. field_tx_fifo_thresh = REG_FIELD ( JZ_REG_AIC_CONF , 16 , 20 ) ,
. field_i2sdiv_capture = REG_FIELD ( JZ_REG_AIC_CLK_DIV , 8 , 11 ) ,
. field_i2sdiv_playback = REG_FIELD ( JZ_REG_AIC_CLK_DIV , 0 , 3 ) ,
2020-03-06 23:29:29 +01:00
} ;
2022-10-23 15:33:27 +01:00
static int jz4740_i2s_suspend ( struct snd_soc_component * component )
{
struct jz4740_i2s * i2s = snd_soc_component_get_drvdata ( component ) ;
if ( snd_soc_component_active ( component ) ) {
regmap_clear_bits ( i2s - > regmap , JZ_REG_AIC_CONF , JZ_AIC_CONF_ENABLE ) ;
clk_disable_unprepare ( i2s - > clk_i2s ) ;
}
clk_disable_unprepare ( i2s - > clk_aic ) ;
return 0 ;
}
static int jz4740_i2s_resume ( struct snd_soc_component * component )
{
struct jz4740_i2s * i2s = snd_soc_component_get_drvdata ( component ) ;
int ret ;
ret = clk_prepare_enable ( i2s - > clk_aic ) ;
if ( ret )
return ret ;
if ( snd_soc_component_active ( component ) ) {
ret = clk_prepare_enable ( i2s - > clk_i2s ) ;
if ( ret ) {
clk_disable_unprepare ( i2s - > clk_aic ) ;
return ret ;
}
regmap_set_bits ( i2s - > regmap , JZ_REG_AIC_CONF , JZ_AIC_CONF_ENABLE ) ;
}
return 0 ;
}
2022-10-23 15:33:28 +01:00
static int jz4740_i2s_probe ( struct snd_soc_component * component )
{
struct jz4740_i2s * i2s = snd_soc_component_get_drvdata ( component ) ;
int ret ;
ret = clk_prepare_enable ( i2s - > clk_aic ) ;
if ( ret )
return ret ;
regmap_write ( i2s - > regmap , JZ_REG_AIC_CONF , JZ_AIC_CONF_RESET ) ;
regmap_write ( i2s - > regmap , JZ_REG_AIC_CONF ,
JZ_AIC_CONF_OVERFLOW_PLAY_LAST |
JZ_AIC_CONF_I2S | JZ_AIC_CONF_INTERNAL_CODEC ) ;
regmap_field_write ( i2s - > field_rx_fifo_thresh , 7 ) ;
regmap_field_write ( i2s - > field_tx_fifo_thresh , 8 ) ;
return 0 ;
}
static void jz4740_i2s_remove ( struct snd_soc_component * component )
{
struct jz4740_i2s * i2s = snd_soc_component_get_drvdata ( component ) ;
clk_disable_unprepare ( i2s - > clk_aic ) ;
}
2013-03-21 03:32:28 -07:00
static const struct snd_soc_component_driver jz4740_i2s_component = {
2022-06-23 13:51:20 +01:00
. name = " jz4740-i2s " ,
2022-10-23 15:33:28 +01:00
. probe = jz4740_i2s_probe ,
. remove = jz4740_i2s_remove ,
2022-06-23 13:51:20 +01:00
. suspend = jz4740_i2s_suspend ,
. resume = jz4740_i2s_resume ,
. legacy_dai_naming = 1 ,
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
2022-10-23 15:33:22 +01:00
static int jz4740_i2s_init_regmap_fields ( struct device * dev ,
struct jz4740_i2s * i2s )
{
i2s - > field_rx_fifo_thresh =
devm_regmap_field_alloc ( dev , i2s - > regmap ,
i2s - > soc_info - > field_rx_fifo_thresh ) ;
if ( IS_ERR ( i2s - > field_rx_fifo_thresh ) )
return PTR_ERR ( i2s - > field_rx_fifo_thresh ) ;
i2s - > field_tx_fifo_thresh =
devm_regmap_field_alloc ( dev , i2s - > regmap ,
i2s - > soc_info - > field_tx_fifo_thresh ) ;
if ( IS_ERR ( i2s - > field_tx_fifo_thresh ) )
return PTR_ERR ( i2s - > field_tx_fifo_thresh ) ;
i2s - > field_i2sdiv_capture =
devm_regmap_field_alloc ( dev , i2s - > regmap ,
i2s - > soc_info - > field_i2sdiv_capture ) ;
if ( IS_ERR ( i2s - > field_i2sdiv_capture ) )
return PTR_ERR ( i2s - > field_i2sdiv_capture ) ;
i2s - > field_i2sdiv_playback =
devm_regmap_field_alloc ( dev , i2s - > regmap ,
i2s - > soc_info - > field_i2sdiv_playback ) ;
if ( IS_ERR ( i2s - > field_i2sdiv_playback ) )
return PTR_ERR ( i2s - > field_i2sdiv_playback ) ;
return 0 ;
}
2022-10-23 15:33:21 +01:00
static const struct regmap_config jz4740_i2s_regmap_config = {
. reg_bits = 32 ,
. reg_stride = 4 ,
. val_bits = 32 ,
. max_register = JZ_REG_AIC_FIFO ,
} ;
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 ;
2022-10-23 15:33:21 +01:00
void __iomem * regs ;
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
2022-10-23 15:33:21 +01:00
regs = devm_platform_get_and_ioremap_resource ( pdev , 0 , & mem ) ;
if ( IS_ERR ( regs ) )
return PTR_ERR ( regs ) ;
2010-06-19 16:50:37 +02:00
2022-07-06 22:13:21 +01:00
i2s - > playback_dma_data . maxburst = 16 ;
i2s - > playback_dma_data . addr = mem - > start + JZ_REG_AIC_FIFO ;
i2s - > capture_dma_data . maxburst = 16 ;
i2s - > capture_dma_data . addr = mem - > start + JZ_REG_AIC_FIFO ;
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
2022-10-23 15:33:21 +01:00
i2s - > regmap = devm_regmap_init_mmio ( & pdev - > dev , regs ,
& jz4740_i2s_regmap_config ) ;
if ( IS_ERR ( i2s - > regmap ) )
return PTR_ERR ( i2s - > regmap ) ;
2022-10-23 15:33:22 +01:00
ret = jz4740_i2s_init_regmap_fields ( dev , i2s ) ;
if ( ret )
return ret ;
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 " ) ;