2019-05-29 16:57:50 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2011-07-05 10:55:27 -06:00
/*
2012-04-05 15:54:53 -06:00
* tegra20_spdif . c - Tegra20 SPDIF driver
2011-07-05 10:55:27 -06:00
*
* Author : Stephen Warren < swarren @ nvidia . com >
2012-03-20 14:55:49 -06:00
* Copyright ( C ) 2011 - 2012 - NVIDIA , Inc .
2011-07-05 10:55:27 -06:00
*/
# include <linux/clk.h>
2021-12-04 17:37:13 +03:00
# include <linux/delay.h>
2011-07-05 10:55:27 -06:00
# include <linux/device.h>
2012-04-06 11:12:25 -06:00
# include <linux/io.h>
# include <linux/module.h>
2021-12-04 17:37:10 +03:00
# include <linux/of_device.h>
2011-07-05 10:55:27 -06:00
# include <linux/platform_device.h>
2012-04-09 09:52:22 -06:00
# include <linux/pm_runtime.h>
2012-04-13 12:14:07 -06:00
# include <linux/regmap.h>
2021-12-04 17:37:13 +03:00
# include <linux/reset.h>
2011-07-05 10:55:27 -06:00
# include <linux/slab.h>
# include <sound/core.h>
# include <sound/pcm.h>
# include <sound/pcm_params.h>
# include <sound/soc.h>
2013-04-03 11:06:03 +02:00
# include <sound/dmaengine_pcm.h>
2011-07-05 10:55:27 -06:00
2012-04-05 15:54:53 -06:00
# include "tegra20_spdif.h"
2011-07-05 10:55:27 -06:00
2021-04-22 15:34:00 +02:00
static __maybe_unused int tegra20_spdif_runtime_suspend ( struct device * dev )
2012-04-09 09:52:22 -06:00
{
struct tegra20_spdif * spdif = dev_get_drvdata ( dev ) ;
2021-12-04 17:37:13 +03:00
regcache_cache_only ( spdif - > regmap , true ) ;
2012-06-05 09:59:42 +05:30
clk_disable_unprepare ( spdif - > clk_spdif_out ) ;
2012-04-09 09:52:22 -06:00
return 0 ;
}
2021-04-22 15:34:00 +02:00
static __maybe_unused int tegra20_spdif_runtime_resume ( struct device * dev )
2012-04-09 09:52:22 -06:00
{
struct tegra20_spdif * spdif = dev_get_drvdata ( dev ) ;
int ret ;
2021-12-04 17:37:13 +03:00
ret = reset_control_assert ( spdif - > reset ) ;
if ( ret )
return ret ;
2012-06-05 09:59:42 +05:30
ret = clk_prepare_enable ( spdif - > clk_spdif_out ) ;
2012-04-09 09:52:22 -06:00
if ( ret ) {
dev_err ( dev , " clk_enable failed: %d \n " , ret ) ;
return ret ;
}
2021-12-04 17:37:13 +03:00
usleep_range ( 10 , 100 ) ;
ret = reset_control_deassert ( spdif - > reset ) ;
if ( ret )
goto disable_clocks ;
regcache_cache_only ( spdif - > regmap , false ) ;
regcache_mark_dirty ( spdif - > regmap ) ;
ret = regcache_sync ( spdif - > regmap ) ;
if ( ret )
goto disable_clocks ;
2012-04-09 09:52:22 -06:00
return 0 ;
2021-12-04 17:37:13 +03:00
disable_clocks :
clk_disable_unprepare ( spdif - > clk_spdif_out ) ;
return ret ;
2012-04-09 09:52:22 -06:00
}
2012-04-06 10:30:52 -06:00
static int tegra20_spdif_hw_params ( struct snd_pcm_substream * substream ,
2021-12-04 17:37:11 +03:00
struct snd_pcm_hw_params * params ,
struct snd_soc_dai * dai )
2011-07-05 10:55:27 -06:00
{
2021-12-04 17:37:11 +03:00
struct tegra20_spdif * spdif = dev_get_drvdata ( dai - > dev ) ;
2013-12-06 13:34:50 -07:00
unsigned int mask = 0 , val = 0 ;
2011-10-02 21:07:02 +08:00
int ret , spdifclock ;
2021-12-04 17:37:15 +03:00
long rate ;
2011-07-05 10:55:27 -06:00
2013-12-06 13:34:50 -07:00
mask | = TEGRA20_SPDIF_CTRL_PACK |
TEGRA20_SPDIF_CTRL_BIT_MODE_MASK ;
2011-07-05 10:55:27 -06:00
switch ( params_format ( params ) ) {
case SNDRV_PCM_FORMAT_S16_LE :
2013-12-06 13:34:50 -07:00
val | = TEGRA20_SPDIF_CTRL_PACK |
TEGRA20_SPDIF_CTRL_BIT_MODE_16BIT ;
2011-07-05 10:55:27 -06:00
break ;
default :
return - EINVAL ;
}
2012-06-06 17:15:06 -06:00
regmap_update_bits ( spdif - > regmap , TEGRA20_SPDIF_CTRL , mask , val ) ;
2021-12-04 17:37:08 +03:00
/*
* FIFO trigger level must be bigger than DMA burst or equal to it ,
* otherwise data is discarded on overflow .
*/
regmap_update_bits ( spdif - > regmap , TEGRA20_SPDIF_DATA_FIFO_CSR ,
TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_MASK ,
TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU4_WORD_FULL ) ;
2011-07-05 10:55:27 -06:00
switch ( params_rate ( params ) ) {
case 32000 :
spdifclock = 4096000 ;
break ;
case 44100 :
spdifclock = 5644800 ;
break ;
case 48000 :
spdifclock = 6144000 ;
break ;
case 88200 :
spdifclock = 11289600 ;
break ;
case 96000 :
spdifclock = 12288000 ;
break ;
case 176400 :
spdifclock = 22579200 ;
break ;
case 192000 :
spdifclock = 24576000 ;
break ;
default :
return - EINVAL ;
}
ret = clk_set_rate ( spdif - > clk_spdif_out , spdifclock ) ;
if ( ret ) {
2021-12-04 17:37:11 +03:00
dev_err ( dai - > dev , " Can't set SPDIF clock rate: %d \n " , ret ) ;
2011-07-05 10:55:27 -06:00
return ret ;
}
2021-12-04 17:37:15 +03:00
rate = clk_get_rate ( spdif - > clk_spdif_out ) ;
if ( rate ! = spdifclock )
dev_warn_once ( dai - > dev ,
" SPDIF clock rate %d doesn't match requested rate %lu \n " ,
spdifclock , rate ) ;
2011-07-05 10:55:27 -06:00
return 0 ;
}
2012-04-06 10:30:52 -06:00
static void tegra20_spdif_start_playback ( struct tegra20_spdif * spdif )
2011-07-05 10:55:27 -06:00
{
2012-06-06 17:15:06 -06:00
regmap_update_bits ( spdif - > regmap , TEGRA20_SPDIF_CTRL ,
TEGRA20_SPDIF_CTRL_TX_EN ,
TEGRA20_SPDIF_CTRL_TX_EN ) ;
2011-07-05 10:55:27 -06:00
}
2012-04-06 10:30:52 -06:00
static void tegra20_spdif_stop_playback ( struct tegra20_spdif * spdif )
2011-07-05 10:55:27 -06:00
{
2012-06-06 17:15:06 -06:00
regmap_update_bits ( spdif - > regmap , TEGRA20_SPDIF_CTRL ,
TEGRA20_SPDIF_CTRL_TX_EN , 0 ) ;
2011-07-05 10:55:27 -06:00
}
2012-04-06 10:30:52 -06:00
static int tegra20_spdif_trigger ( struct snd_pcm_substream * substream , int cmd ,
2021-12-04 17:37:11 +03:00
struct snd_soc_dai * dai )
2011-07-05 10:55:27 -06:00
{
2021-12-04 17:37:11 +03:00
struct tegra20_spdif * spdif = dev_get_drvdata ( dai - > dev ) ;
2011-07-05 10:55:27 -06:00
switch ( cmd ) {
case SNDRV_PCM_TRIGGER_START :
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE :
case SNDRV_PCM_TRIGGER_RESUME :
2012-04-06 10:30:52 -06:00
tegra20_spdif_start_playback ( spdif ) ;
2011-07-05 10:55:27 -06:00
break ;
case SNDRV_PCM_TRIGGER_STOP :
case SNDRV_PCM_TRIGGER_PAUSE_PUSH :
case SNDRV_PCM_TRIGGER_SUSPEND :
2012-04-06 10:30:52 -06:00
tegra20_spdif_stop_playback ( spdif ) ;
2011-07-05 10:55:27 -06:00
break ;
default :
return - EINVAL ;
}
return 0 ;
}
2021-12-04 17:37:15 +03:00
static int tegra20_spdif_filter_rates ( struct snd_pcm_hw_params * params ,
struct snd_pcm_hw_rule * rule )
{
struct snd_interval * r = hw_param_interval ( params , rule - > var ) ;
struct snd_soc_dai * dai = rule - > private ;
struct tegra20_spdif * spdif = dev_get_drvdata ( dai - > dev ) ;
struct clk * parent = clk_get_parent ( spdif - > clk_spdif_out ) ;
2022-02-14 21:32:23 +00:00
static const unsigned int rates [ ] = { 32000 , 44100 , 48000 } ;
2023-06-08 07:27:22 +02:00
unsigned long i , parent_rate , valid_rates = 0 ;
2021-12-04 17:37:15 +03:00
parent_rate = clk_get_rate ( parent ) ;
2023-06-08 07:27:22 +02:00
if ( ! parent_rate ) {
dev_err ( dai - > dev , " Can't get parent clock rate \n " ) ;
return - EINVAL ;
2021-12-04 17:37:15 +03:00
}
for ( i = 0 ; i < ARRAY_SIZE ( rates ) ; i + + ) {
if ( parent_rate % ( rates [ i ] * 128 ) = = 0 )
valid_rates | = BIT ( i ) ;
}
/*
* At least one rate must be valid , otherwise the parent clock isn ' t
* audio PLL . Nothing should be filtered in this case .
*/
if ( ! valid_rates )
valid_rates = BIT ( ARRAY_SIZE ( rates ) ) - 1 ;
return snd_interval_list ( r , ARRAY_SIZE ( rates ) , rates , valid_rates ) ;
}
static int tegra20_spdif_startup ( struct snd_pcm_substream * substream ,
struct snd_soc_dai * dai )
{
if ( ! device_property_read_bool ( dai - > dev , " nvidia,fixed-parent-rate " ) )
return 0 ;
/*
* SPDIF and I2S share audio PLL . HDMI takes audio packets from SPDIF
* and audio may not work on some TVs if clock rate isn ' t precise .
*
* PLL rate is controlled by I2S side . Filter out audio rates that
* don ' t match PLL rate at the start of stream to allow both SPDIF
* and I2S work simultaneously , assuming that PLL rate won ' t be
* changed later on .
*/
return snd_pcm_hw_rule_add ( substream - > runtime , 0 ,
SNDRV_PCM_HW_PARAM_RATE ,
tegra20_spdif_filter_rates , dai ,
SNDRV_PCM_HW_PARAM_RATE , - 1 ) ;
}
2012-04-06 10:30:52 -06:00
static int tegra20_spdif_probe ( struct snd_soc_dai * dai )
2011-07-05 10:55:27 -06:00
{
2021-12-04 17:37:11 +03:00
struct tegra20_spdif * spdif = dev_get_drvdata ( dai - > dev ) ;
2011-07-05 10:55:27 -06:00
2023-01-31 02:01:13 +00:00
snd_soc_dai_init_dma_data ( dai , & spdif - > playback_dma_data , NULL ) ;
2011-07-05 10:55:27 -06:00
return 0 ;
}
2012-04-06 10:30:52 -06:00
static const struct snd_soc_dai_ops tegra20_spdif_dai_ops = {
2021-12-04 17:37:11 +03:00
. hw_params = tegra20_spdif_hw_params ,
. trigger = tegra20_spdif_trigger ,
2021-12-04 17:37:15 +03:00
. startup = tegra20_spdif_startup ,
2011-07-05 10:55:27 -06:00
} ;
2012-04-06 10:30:52 -06:00
static struct snd_soc_dai_driver tegra20_spdif_dai = {
2021-12-04 17:37:11 +03:00
. name = " tegra20-spdif " ,
2012-04-06 10:30:52 -06:00
. probe = tegra20_spdif_probe ,
2011-07-05 10:55:27 -06:00
. playback = {
2012-06-06 17:15:07 -06:00
. stream_name = " Playback " ,
2011-07-05 10:55:27 -06:00
. channels_min = 2 ,
. channels_max = 2 ,
. rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
2021-12-04 17:37:11 +03:00
SNDRV_PCM_RATE_48000 ,
2011-07-05 10:55:27 -06:00
. formats = SNDRV_PCM_FMTBIT_S16_LE ,
} ,
2012-04-06 10:30:52 -06:00
. ops = & tegra20_spdif_dai_ops ,
2011-07-05 10:55:27 -06:00
} ;
2013-03-21 03:37:33 -07:00
static const struct snd_soc_component_driver tegra20_spdif_component = {
2021-12-04 17:37:11 +03:00
. name = " tegra20-spdif " ,
2022-06-23 13:51:25 +01:00
. legacy_dai_naming = 1 ,
2013-03-21 03:37:33 -07:00
} ;
2012-04-13 12:14:07 -06:00
static bool tegra20_spdif_wr_rd_reg ( struct device * dev , unsigned int reg )
{
switch ( reg ) {
case TEGRA20_SPDIF_CTRL :
case TEGRA20_SPDIF_STATUS :
case TEGRA20_SPDIF_STROBE_CTRL :
case TEGRA20_SPDIF_DATA_FIFO_CSR :
case TEGRA20_SPDIF_DATA_OUT :
case TEGRA20_SPDIF_DATA_IN :
case TEGRA20_SPDIF_CH_STA_RX_A :
case TEGRA20_SPDIF_CH_STA_RX_B :
case TEGRA20_SPDIF_CH_STA_RX_C :
case TEGRA20_SPDIF_CH_STA_RX_D :
case TEGRA20_SPDIF_CH_STA_RX_E :
case TEGRA20_SPDIF_CH_STA_RX_F :
case TEGRA20_SPDIF_CH_STA_TX_A :
case TEGRA20_SPDIF_CH_STA_TX_B :
case TEGRA20_SPDIF_CH_STA_TX_C :
case TEGRA20_SPDIF_CH_STA_TX_D :
case TEGRA20_SPDIF_CH_STA_TX_E :
case TEGRA20_SPDIF_CH_STA_TX_F :
case TEGRA20_SPDIF_USR_STA_RX_A :
case TEGRA20_SPDIF_USR_DAT_TX_A :
return true ;
default :
return false ;
2013-10-08 15:55:45 -07:00
}
2012-04-13 12:14:07 -06:00
}
static bool tegra20_spdif_volatile_reg ( struct device * dev , unsigned int reg )
{
switch ( reg ) {
case TEGRA20_SPDIF_STATUS :
case TEGRA20_SPDIF_DATA_FIFO_CSR :
case TEGRA20_SPDIF_DATA_OUT :
case TEGRA20_SPDIF_DATA_IN :
case TEGRA20_SPDIF_CH_STA_RX_A :
case TEGRA20_SPDIF_CH_STA_RX_B :
case TEGRA20_SPDIF_CH_STA_RX_C :
case TEGRA20_SPDIF_CH_STA_RX_D :
case TEGRA20_SPDIF_CH_STA_RX_E :
case TEGRA20_SPDIF_CH_STA_RX_F :
case TEGRA20_SPDIF_USR_STA_RX_A :
case TEGRA20_SPDIF_USR_DAT_TX_A :
return true ;
default :
return false ;
2013-10-08 15:55:45 -07:00
}
2012-04-13 12:14:07 -06:00
}
static bool tegra20_spdif_precious_reg ( struct device * dev , unsigned int reg )
{
switch ( reg ) {
case TEGRA20_SPDIF_DATA_OUT :
case TEGRA20_SPDIF_DATA_IN :
case TEGRA20_SPDIF_USR_STA_RX_A :
case TEGRA20_SPDIF_USR_DAT_TX_A :
return true ;
default :
return false ;
2013-10-08 15:55:45 -07:00
}
2012-04-13 12:14:07 -06:00
}
static const struct regmap_config tegra20_spdif_regmap_config = {
. reg_bits = 32 ,
. reg_stride = 4 ,
. val_bits = 32 ,
. max_register = TEGRA20_SPDIF_USR_DAT_TX_A ,
. writeable_reg = tegra20_spdif_wr_rd_reg ,
. readable_reg = tegra20_spdif_wr_rd_reg ,
. volatile_reg = tegra20_spdif_volatile_reg ,
. precious_reg = tegra20_spdif_precious_reg ,
2014-03-17 22:08:49 -07:00
. cache_type = REGCACHE_FLAT ,
2012-04-13 12:14:07 -06:00
} ;
2012-12-07 09:26:33 -05:00
static int tegra20_spdif_platform_probe ( struct platform_device * pdev )
2011-07-05 10:55:27 -06:00
{
2012-04-06 10:30:52 -06:00
struct tegra20_spdif * spdif ;
2021-12-04 17:37:11 +03:00
struct resource * mem ;
2012-04-13 12:14:07 -06:00
void __iomem * regs ;
2011-07-05 10:55:27 -06:00
int ret ;
2012-04-06 11:14:04 -06:00
spdif = devm_kzalloc ( & pdev - > dev , sizeof ( struct tegra20_spdif ) ,
GFP_KERNEL ) ;
2017-02-25 13:18:08 +02:00
if ( ! spdif )
2015-08-13 12:59:21 +05:30
return - ENOMEM ;
2017-02-25 13:18:08 +02:00
2011-07-05 10:55:27 -06:00
dev_set_drvdata ( & pdev - > dev , spdif ) ;
2021-12-04 17:37:13 +03:00
spdif - > reset = devm_reset_control_get_exclusive ( & pdev - > dev , NULL ) ;
if ( IS_ERR ( spdif - > reset ) ) {
dev_err ( & pdev - > dev , " Can't retrieve spdif reset \n " ) ;
return PTR_ERR ( spdif - > reset ) ;
}
2021-12-04 17:37:10 +03:00
spdif - > clk_spdif_out = devm_clk_get ( & pdev - > dev , " out " ) ;
2011-07-05 10:55:27 -06:00
if ( IS_ERR ( spdif - > clk_spdif_out ) ) {
2021-12-04 17:37:11 +03:00
dev_err ( & pdev - > dev , " Could not retrieve spdif clock \n " ) ;
return PTR_ERR ( spdif - > clk_spdif_out ) ;
2011-07-05 10:55:27 -06:00
}
2021-06-18 10:47:20 +08:00
regs = devm_platform_get_and_ioremap_resource ( pdev , 0 , & mem ) ;
2015-08-23 23:32:14 +08:00
if ( IS_ERR ( regs ) )
return PTR_ERR ( regs ) ;
2011-07-05 10:55:27 -06:00
2012-04-13 12:14:07 -06:00
spdif - > regmap = devm_regmap_init_mmio ( & pdev - > dev , regs ,
2021-12-04 17:37:11 +03:00
& tegra20_spdif_regmap_config ) ;
2012-04-13 12:14:07 -06:00
if ( IS_ERR ( spdif - > regmap ) ) {
dev_err ( & pdev - > dev , " regmap init failed \n " ) ;
2021-12-04 17:37:11 +03:00
return PTR_ERR ( spdif - > regmap ) ;
2012-04-13 12:14:07 -06:00
}
2012-04-06 10:30:52 -06:00
spdif - > playback_dma_data . addr = mem - > start + TEGRA20_SPDIF_DATA_OUT ;
2013-07-21 10:34:09 +08:00
spdif - > playback_dma_data . addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES ;
spdif - > playback_dma_data . maxburst = 4 ;
2011-07-05 10:55:27 -06:00
2021-12-04 17:37:12 +03:00
ret = devm_pm_runtime_enable ( & pdev - > dev ) ;
if ( ret )
return ret ;
2012-04-09 09:52:22 -06:00
2021-12-04 17:37:12 +03:00
ret = devm_snd_soc_register_component ( & pdev - > dev ,
& tegra20_spdif_component ,
& tegra20_spdif_dai , 1 ) ;
2011-07-05 10:55:27 -06:00
if ( ret ) {
dev_err ( & pdev - > dev , " Could not register DAI: %d \n " , ret ) ;
2021-12-04 17:37:12 +03:00
return ret ;
2011-07-05 10:55:27 -06:00
}
2021-12-04 17:37:12 +03:00
ret = devm_tegra_pcm_platform_register ( & pdev - > dev ) ;
2012-03-20 14:55:49 -06:00
if ( ret ) {
dev_err ( & pdev - > dev , " Could not register PCM: %d \n " , ret ) ;
2021-12-04 17:37:12 +03:00
return ret ;
2012-03-20 14:55:49 -06:00
}
2011-07-05 10:55:27 -06:00
return 0 ;
}
2012-11-19 13:25:33 -05:00
static const struct dev_pm_ops tegra20_spdif_pm_ops = {
2012-04-09 09:52:22 -06:00
SET_RUNTIME_PM_OPS ( tegra20_spdif_runtime_suspend ,
tegra20_spdif_runtime_resume , NULL )
2021-12-04 17:37:14 +03:00
SET_SYSTEM_SLEEP_PM_OPS ( pm_runtime_force_suspend ,
pm_runtime_force_resume )
2012-04-09 09:52:22 -06:00
} ;
2021-12-04 17:37:10 +03:00
static const struct of_device_id tegra20_spdif_of_match [ ] = {
{ . compatible = " nvidia,tegra20-spdif " , } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , tegra20_spdif_of_match ) ;
2012-04-06 10:30:52 -06:00
static struct platform_driver tegra20_spdif_driver = {
2011-07-05 10:55:27 -06:00
. driver = {
2021-12-04 17:37:11 +03:00
. name = " tegra20-spdif " ,
2012-04-09 09:52:22 -06:00
. pm = & tegra20_spdif_pm_ops ,
2021-12-04 17:37:10 +03:00
. of_match_table = tegra20_spdif_of_match ,
2011-07-05 10:55:27 -06:00
} ,
2012-04-06 10:30:52 -06:00
. probe = tegra20_spdif_platform_probe ,
2011-07-05 10:55:27 -06:00
} ;
2012-04-06 10:30:52 -06:00
module_platform_driver ( tegra20_spdif_driver ) ;
2011-07-05 10:55:27 -06:00
MODULE_AUTHOR ( " Stephen Warren <swarren@nvidia.com> " ) ;
2012-04-06 10:30:52 -06:00
MODULE_DESCRIPTION ( " Tegra20 SPDIF ASoC driver " ) ;
2011-07-05 10:55:27 -06:00
MODULE_LICENSE ( " GPL " ) ;