2018-12-11 14:47:12 +01:00
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
//
// Copyright (c) 2018 BayLibre, SAS.
// Author: Jerome Brunet <jbrunet@baylibre.com>
# include <linux/bitfield.h>
# include <linux/clk.h>
# include <linux/module.h>
# include <linux/of_platform.h>
# include <linux/regmap.h>
# include <sound/soc.h>
# include <sound/soc-dai.h>
# include <sound/pcm_params.h>
# define SPDIFIN_CTRL0 0x00
# define SPDIFIN_CTRL0_EN BIT(31)
# define SPDIFIN_CTRL0_RST_OUT BIT(29)
# define SPDIFIN_CTRL0_RST_IN BIT(28)
# define SPDIFIN_CTRL0_WIDTH_SEL BIT(24)
# define SPDIFIN_CTRL0_STATUS_CH_SHIFT 11
# define SPDIFIN_CTRL0_STATUS_SEL GENMASK(10, 8)
# define SPDIFIN_CTRL0_SRC_SEL GENMASK(5, 4)
# define SPDIFIN_CTRL0_CHK_VALID BIT(3)
# define SPDIFIN_CTRL1 0x04
# define SPDIFIN_CTRL1_BASE_TIMER GENMASK(19, 0)
# define SPDIFIN_CTRL1_IRQ_MASK GENMASK(27, 20)
# define SPDIFIN_CTRL2 0x08
# define SPDIFIN_THRES_PER_REG 3
# define SPDIFIN_THRES_WIDTH 10
# define SPDIFIN_CTRL3 0x0c
# define SPDIFIN_CTRL4 0x10
# define SPDIFIN_TIMER_PER_REG 4
# define SPDIFIN_TIMER_WIDTH 8
# define SPDIFIN_CTRL5 0x14
# define SPDIFIN_CTRL6 0x18
# define SPDIFIN_STAT0 0x1c
# define SPDIFIN_STAT0_MODE GENMASK(30, 28)
# define SPDIFIN_STAT0_MAXW GENMASK(17, 8)
# define SPDIFIN_STAT0_IRQ GENMASK(7, 0)
# define SPDIFIN_IRQ_MODE_CHANGED BIT(2)
# define SPDIFIN_STAT1 0x20
# define SPDIFIN_STAT2 0x24
# define SPDIFIN_MUTE_VAL 0x28
# define SPDIFIN_MODE_NUM 7
struct axg_spdifin_cfg {
const unsigned int * mode_rates ;
unsigned int ref_rate ;
} ;
struct axg_spdifin {
const struct axg_spdifin_cfg * conf ;
struct regmap * map ;
struct clk * refclk ;
struct clk * pclk ;
} ;
/*
* TODO :
* It would have been nice to check the actual rate against the sample rate
* requested in hw_params ( ) . Unfortunately , I was not able to make the mode
* detection and IRQ work reliably :
*
* 1. IRQs are generated on mode change only , so there is no notification
* on transition between no signal and mode 0 ( 32 kHz ) .
* 2. Mode detection very often has glitches , and may detects the
* lowest or the highest mode before zeroing in on the actual mode .
*
* This makes calling snd_pcm_stop ( ) difficult to get right . Even notifying
* the kcontrol would be very unreliable at this point .
* Let ' s keep things simple until the magic spell that makes this work is
* found .
*/
static unsigned int axg_spdifin_get_rate ( struct axg_spdifin * priv )
{
unsigned int stat , mode , rate = 0 ;
regmap_read ( priv - > map , SPDIFIN_STAT0 , & stat ) ;
mode = FIELD_GET ( SPDIFIN_STAT0_MODE , stat ) ;
/*
* If max width is zero , we are not capturing anything .
* Also Sometimes , when the capture is on but there is no data ,
* mode is SPDIFIN_MODE_NUM , but not always . . .
*/
if ( FIELD_GET ( SPDIFIN_STAT0_MAXW , stat ) & &
mode < SPDIFIN_MODE_NUM )
rate = priv - > conf - > mode_rates [ mode ] ;
return rate ;
}
static int axg_spdifin_prepare ( struct snd_pcm_substream * substream ,
struct snd_soc_dai * dai )
{
struct axg_spdifin * priv = snd_soc_dai_get_drvdata ( dai ) ;
/* Apply both reset */
regmap_update_bits ( priv - > map , SPDIFIN_CTRL0 ,
SPDIFIN_CTRL0_RST_OUT |
SPDIFIN_CTRL0_RST_IN ,
0 ) ;
/* Clear out reset before in reset */
regmap_update_bits ( priv - > map , SPDIFIN_CTRL0 ,
SPDIFIN_CTRL0_RST_OUT , SPDIFIN_CTRL0_RST_OUT ) ;
regmap_update_bits ( priv - > map , SPDIFIN_CTRL0 ,
SPDIFIN_CTRL0_RST_IN , SPDIFIN_CTRL0_RST_IN ) ;
return 0 ;
}
static int axg_spdifin_startup ( struct snd_pcm_substream * substream ,
struct snd_soc_dai * dai )
{
struct axg_spdifin * priv = snd_soc_dai_get_drvdata ( dai ) ;
int ret ;
ret = clk_prepare_enable ( priv - > refclk ) ;
if ( ret ) {
dev_err ( dai - > dev ,
" failed to enable spdifin reference clock \n " ) ;
return ret ;
}
regmap_update_bits ( priv - > map , SPDIFIN_CTRL0 , SPDIFIN_CTRL0_EN ,
SPDIFIN_CTRL0_EN ) ;
return 0 ;
}
static void axg_spdifin_shutdown ( struct snd_pcm_substream * substream ,
struct snd_soc_dai * dai )
{
struct axg_spdifin * priv = snd_soc_dai_get_drvdata ( dai ) ;
regmap_update_bits ( priv - > map , SPDIFIN_CTRL0 , SPDIFIN_CTRL0_EN , 0 ) ;
clk_disable_unprepare ( priv - > refclk ) ;
}
static void axg_spdifin_write_mode_param ( struct regmap * map , int mode ,
unsigned int val ,
unsigned int num_per_reg ,
unsigned int base_reg ,
unsigned int width )
{
2018-12-13 16:44:28 +01:00
uint64_t offset = mode ;
unsigned int reg , shift , rem ;
2018-12-11 14:47:12 +01:00
rem = do_div ( offset , num_per_reg ) ;
reg = offset * regmap_get_reg_stride ( map ) + base_reg ;
shift = width * ( num_per_reg - 1 - rem ) ;
regmap_update_bits ( map , reg , GENMASK ( width - 1 , 0 ) < < shift ,
val < < shift ) ;
}
static void axg_spdifin_write_timer ( struct regmap * map , int mode ,
unsigned int val )
{
axg_spdifin_write_mode_param ( map , mode , val , SPDIFIN_TIMER_PER_REG ,
SPDIFIN_CTRL4 , SPDIFIN_TIMER_WIDTH ) ;
}
static void axg_spdifin_write_threshold ( struct regmap * map , int mode ,
unsigned int val )
{
axg_spdifin_write_mode_param ( map , mode , val , SPDIFIN_THRES_PER_REG ,
SPDIFIN_CTRL2 , SPDIFIN_THRES_WIDTH ) ;
}
static unsigned int axg_spdifin_mode_timer ( struct axg_spdifin * priv ,
int mode ,
unsigned int rate )
{
/*
* Number of period of the reference clock during a period of the
* input signal reference clock
*/
return rate / ( 128 * priv - > conf - > mode_rates [ mode ] ) ;
}
static int axg_spdifin_sample_mode_config ( struct snd_soc_dai * dai ,
struct axg_spdifin * priv )
{
unsigned int rate , t_next ;
int ret , i = SPDIFIN_MODE_NUM - 1 ;
/* Set spdif input reference clock */
ret = clk_set_rate ( priv - > refclk , priv - > conf - > ref_rate ) ;
if ( ret ) {
dev_err ( dai - > dev , " reference clock rate set failed \n " ) ;
return ret ;
}
/*
* The rate actually set might be slightly different , get
* the actual rate for the following mode calculation
*/
rate = clk_get_rate ( priv - > refclk ) ;
/* HW will update mode every 1ms */
regmap_update_bits ( priv - > map , SPDIFIN_CTRL1 ,
SPDIFIN_CTRL1_BASE_TIMER ,
FIELD_PREP ( SPDIFIN_CTRL1_BASE_TIMER , rate / 1000 ) ) ;
/* Threshold based on the minimum width between two edges */
regmap_update_bits ( priv - > map , SPDIFIN_CTRL0 ,
SPDIFIN_CTRL0_WIDTH_SEL , SPDIFIN_CTRL0_WIDTH_SEL ) ;
/* Calculate the last timer which has no threshold */
t_next = axg_spdifin_mode_timer ( priv , i , rate ) ;
axg_spdifin_write_timer ( priv - > map , i , t_next ) ;
do {
unsigned int t ;
i - = 1 ;
/* Calculate the timer */
t = axg_spdifin_mode_timer ( priv , i , rate ) ;
/* Set the timer value */
axg_spdifin_write_timer ( priv - > map , i , t ) ;
/* Set the threshold value */
axg_spdifin_write_threshold ( priv - > map , i , t + t_next ) ;
/* Save the current timer for the next threshold calculation */
t_next = t ;
} while ( i > 0 ) ;
return 0 ;
}
static int axg_spdifin_dai_probe ( struct snd_soc_dai * dai )
{
struct axg_spdifin * priv = snd_soc_dai_get_drvdata ( dai ) ;
int ret ;
ret = clk_prepare_enable ( priv - > pclk ) ;
if ( ret ) {
dev_err ( dai - > dev , " failed to enable pclk \n " ) ;
return ret ;
}
ret = axg_spdifin_sample_mode_config ( dai , priv ) ;
if ( ret ) {
dev_err ( dai - > dev , " mode configuration failed \n " ) ;
clk_disable_unprepare ( priv - > pclk ) ;
return ret ;
}
return 0 ;
}
static int axg_spdifin_dai_remove ( struct snd_soc_dai * dai )
{
struct axg_spdifin * priv = snd_soc_dai_get_drvdata ( dai ) ;
clk_disable_unprepare ( priv - > pclk ) ;
return 0 ;
}
static const struct snd_soc_dai_ops axg_spdifin_ops = {
. prepare = axg_spdifin_prepare ,
. startup = axg_spdifin_startup ,
. shutdown = axg_spdifin_shutdown ,
} ;
static int axg_spdifin_iec958_info ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_info * uinfo )
{
uinfo - > type = SNDRV_CTL_ELEM_TYPE_IEC958 ;
uinfo - > count = 1 ;
return 0 ;
}
static int axg_spdifin_get_status_mask ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
int i ;
for ( i = 0 ; i < 24 ; i + + )
ucontrol - > value . iec958 . status [ i ] = 0xff ;
return 0 ;
}
static int axg_spdifin_get_status ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
struct snd_soc_component * c = snd_kcontrol_chip ( kcontrol ) ;
struct axg_spdifin * priv = snd_soc_component_get_drvdata ( c ) ;
int i , j ;
for ( i = 0 ; i < 6 ; i + + ) {
unsigned int val ;
regmap_update_bits ( priv - > map , SPDIFIN_CTRL0 ,
SPDIFIN_CTRL0_STATUS_SEL ,
FIELD_PREP ( SPDIFIN_CTRL0_STATUS_SEL , i ) ) ;
regmap_read ( priv - > map , SPDIFIN_STAT1 , & val ) ;
for ( j = 0 ; j < 4 ; j + + ) {
unsigned int offset = i * 4 + j ;
ucontrol - > value . iec958 . status [ offset ] =
( val > > ( j * 8 ) ) & 0xff ;
}
}
return 0 ;
}
# define AXG_SPDIFIN_IEC958_MASK \
{ \
. access = SNDRV_CTL_ELEM_ACCESS_READ , \
. iface = SNDRV_CTL_ELEM_IFACE_PCM , \
. name = SNDRV_CTL_NAME_IEC958 ( " " , CAPTURE , MASK ) , \
. info = axg_spdifin_iec958_info , \
. get = axg_spdifin_get_status_mask , \
}
# define AXG_SPDIFIN_IEC958_STATUS \
{ \
. access = ( SNDRV_CTL_ELEM_ACCESS_READ | \
SNDRV_CTL_ELEM_ACCESS_VOLATILE ) , \
. iface = SNDRV_CTL_ELEM_IFACE_PCM , \
. name = SNDRV_CTL_NAME_IEC958 ( " " , CAPTURE , NONE ) , \
. info = axg_spdifin_iec958_info , \
. get = axg_spdifin_get_status , \
}
static const char * const spdifin_chsts_src_texts [ ] = {
" A " , " B " ,
} ;
static SOC_ENUM_SINGLE_DECL ( axg_spdifin_chsts_src_enum , SPDIFIN_CTRL0 ,
SPDIFIN_CTRL0_STATUS_CH_SHIFT ,
spdifin_chsts_src_texts ) ;
static int axg_spdifin_rate_lock_info ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_info * uinfo )
{
uinfo - > type = SNDRV_CTL_ELEM_TYPE_INTEGER ;
uinfo - > count = 1 ;
uinfo - > value . integer . min = 0 ;
uinfo - > value . integer . max = 192000 ;
return 0 ;
}
static int axg_spdifin_rate_lock_get ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
struct snd_soc_component * c = snd_kcontrol_chip ( kcontrol ) ;
struct axg_spdifin * priv = snd_soc_component_get_drvdata ( c ) ;
ucontrol - > value . integer . value [ 0 ] = axg_spdifin_get_rate ( priv ) ;
return 0 ;
}
# define AXG_SPDIFIN_LOCK_RATE(xname) \
{ \
. iface = SNDRV_CTL_ELEM_IFACE_PCM , \
. access = ( SNDRV_CTL_ELEM_ACCESS_READ | \
SNDRV_CTL_ELEM_ACCESS_VOLATILE ) , \
. get = axg_spdifin_rate_lock_get , \
. info = axg_spdifin_rate_lock_info , \
. name = xname , \
}
static const struct snd_kcontrol_new axg_spdifin_controls [ ] = {
AXG_SPDIFIN_LOCK_RATE ( " Capture Rate Lock " ) ,
SOC_DOUBLE ( " Capture Switch " , SPDIFIN_CTRL0 , 7 , 6 , 1 , 1 ) ,
SOC_ENUM ( SNDRV_CTL_NAME_IEC958 ( " " , CAPTURE , NONE ) " Src " ,
axg_spdifin_chsts_src_enum ) ,
AXG_SPDIFIN_IEC958_MASK ,
AXG_SPDIFIN_IEC958_STATUS ,
} ;
static const struct snd_soc_component_driver axg_spdifin_component_drv = {
. controls = axg_spdifin_controls ,
. num_controls = ARRAY_SIZE ( axg_spdifin_controls ) ,
} ;
static const struct regmap_config axg_spdifin_regmap_cfg = {
. reg_bits = 32 ,
. val_bits = 32 ,
. reg_stride = 4 ,
. max_register = SPDIFIN_MUTE_VAL ,
} ;
static const unsigned int axg_spdifin_mode_rates [ SPDIFIN_MODE_NUM ] = {
32000 , 44100 , 48000 , 88200 , 96000 , 176400 , 192000 ,
} ;
static const struct axg_spdifin_cfg axg_cfg = {
. mode_rates = axg_spdifin_mode_rates ,
. ref_rate = 333333333 ,
} ;
static const struct of_device_id axg_spdifin_of_match [ ] = {
{
. compatible = " amlogic,axg-spdifin " ,
. data = & axg_cfg ,
} , { }
} ;
MODULE_DEVICE_TABLE ( of , axg_spdifin_of_match ) ;
static struct snd_soc_dai_driver *
axg_spdifin_get_dai_drv ( struct device * dev , struct axg_spdifin * priv )
{
struct snd_soc_dai_driver * drv ;
int i ;
drv = devm_kzalloc ( dev , sizeof ( * drv ) , GFP_KERNEL ) ;
if ( ! drv )
return ERR_PTR ( - ENOMEM ) ;
drv - > name = " SPDIF Input " ;
drv - > ops = & axg_spdifin_ops ;
drv - > probe = axg_spdifin_dai_probe ;
drv - > remove = axg_spdifin_dai_remove ;
drv - > capture . stream_name = " Capture " ;
drv - > capture . channels_min = 1 ;
drv - > capture . channels_max = 2 ;
drv - > capture . formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE ;
for ( i = 0 ; i < SPDIFIN_MODE_NUM ; i + + ) {
unsigned int rb =
snd_pcm_rate_to_rate_bit ( priv - > conf - > mode_rates [ i ] ) ;
if ( rb = = SNDRV_PCM_RATE_KNOT )
return ERR_PTR ( - EINVAL ) ;
drv - > capture . rates | = rb ;
}
return drv ;
}
static int axg_spdifin_probe ( struct platform_device * pdev )
{
struct device * dev = & pdev - > dev ;
struct axg_spdifin * priv ;
struct snd_soc_dai_driver * dai_drv ;
void __iomem * regs ;
int ret ;
priv = devm_kzalloc ( dev , sizeof ( * priv ) , GFP_KERNEL ) ;
if ( ! priv )
return - ENOMEM ;
platform_set_drvdata ( pdev , priv ) ;
priv - > conf = of_device_get_match_data ( dev ) ;
if ( ! priv - > conf ) {
dev_err ( dev , " failed to match device \n " ) ;
return - ENODEV ;
}
2019-07-27 23:07:32 +08:00
regs = devm_platform_ioremap_resource ( pdev , 0 ) ;
2018-12-11 14:47:12 +01:00
if ( IS_ERR ( regs ) )
return PTR_ERR ( regs ) ;
priv - > map = devm_regmap_init_mmio ( dev , regs , & axg_spdifin_regmap_cfg ) ;
if ( IS_ERR ( priv - > map ) ) {
dev_err ( dev , " failed to init regmap: %ld \n " ,
PTR_ERR ( priv - > map ) ) ;
return PTR_ERR ( priv - > map ) ;
}
priv - > pclk = devm_clk_get ( dev , " pclk " ) ;
if ( IS_ERR ( priv - > pclk ) ) {
ret = PTR_ERR ( priv - > pclk ) ;
if ( ret ! = - EPROBE_DEFER )
dev_err ( dev , " failed to get pclk: %d \n " , ret ) ;
return ret ;
}
priv - > refclk = devm_clk_get ( dev , " refclk " ) ;
if ( IS_ERR ( priv - > refclk ) ) {
ret = PTR_ERR ( priv - > refclk ) ;
if ( ret ! = - EPROBE_DEFER )
dev_err ( dev , " failed to get mclk: %d \n " , ret ) ;
return ret ;
}
dai_drv = axg_spdifin_get_dai_drv ( dev , priv ) ;
if ( IS_ERR ( dai_drv ) ) {
dev_err ( dev , " failed to get dai driver: %ld \n " ,
PTR_ERR ( dai_drv ) ) ;
return PTR_ERR ( dai_drv ) ;
}
return devm_snd_soc_register_component ( dev , & axg_spdifin_component_drv ,
dai_drv , 1 ) ;
}
static struct platform_driver axg_spdifin_pdrv = {
. probe = axg_spdifin_probe ,
. driver = {
. name = " axg-spdifin " ,
. of_match_table = axg_spdifin_of_match ,
} ,
} ;
module_platform_driver ( axg_spdifin_pdrv ) ;
MODULE_DESCRIPTION ( " Amlogic AXG SPDIF Input driver " ) ;
MODULE_AUTHOR ( " Jerome Brunet <jbrunet@baylibre.com> " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;