2013-07-21 21:36:46 -07:00
/*
* Helper routines for R - Car sound ADG .
*
* Copyright ( C ) 2013 Kuninori Morimoto < kuninori . morimoto . gx @ renesas . com >
*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file " COPYING " in the main directory of this archive
* for more details .
*/
# include "rsnd.h"
# define CLKA 0
# define CLKB 1
# define CLKC 2
# define CLKI 3
# define CLKMAX 4
2015-09-10 07:03:48 +00:00
# define BRRx_MASK(x) (0x3FF & x)
2015-09-10 07:02:39 +00:00
static struct rsnd_mod_ops adg_ops = {
. name = " adg " ,
} ;
2013-07-21 21:36:46 -07:00
struct rsnd_adg {
struct clk * clk [ CLKMAX ] ;
2015-09-10 07:02:39 +00:00
struct rsnd_mod mod ;
2013-07-21 21:36:46 -07:00
2015-09-10 07:03:48 +00:00
int rbga_rate_for_441khz ; /* RBGA */
int rbgb_rate_for_48khz ; /* RBGB */
2013-07-21 21:36:46 -07:00
} ;
# define for_each_rsnd_clk(pos, adg, i) \
2014-02-11 17:15:51 -08:00
for ( i = 0 ; \
( i < CLKMAX ) & & \
( ( pos ) = adg - > clk [ i ] ) ; \
i + + )
2013-07-21 21:36:46 -07:00
# define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg)
2015-09-10 07:03:48 +00:00
static u32 rsnd_adg_calculate_rbgx ( unsigned long div )
{
int i , ratio ;
if ( ! div )
return 0 ;
for ( i = 3 ; i > = 0 ; i - - ) {
ratio = 2 < < ( i * 2 ) ;
if ( 0 = = ( div % ratio ) )
return ( u32 ) ( ( i < < 8 ) | ( ( div / ratio ) - 1 ) ) ;
}
return ~ 0 ;
}
2014-01-23 18:42:00 -08:00
2014-03-02 23:43:33 -08:00
static u32 rsnd_adg_ssi_ws_timing_gen2 ( struct rsnd_dai_stream * io )
2014-01-23 18:42:00 -08:00
{
2014-03-02 23:43:33 -08:00
struct rsnd_mod * mod = rsnd_io_to_mod_ssi ( io ) ;
2014-01-23 18:42:00 -08:00
struct rsnd_priv * priv = rsnd_mod_to_priv ( mod ) ;
int id = rsnd_mod_id ( mod ) ;
int ws = id ;
if ( rsnd_ssi_is_pin_sharing ( rsnd_ssi_mod_get ( priv , id ) ) ) {
switch ( id ) {
case 1 :
case 2 :
ws = 0 ;
break ;
case 4 :
ws = 3 ;
break ;
case 8 :
ws = 7 ;
break ;
}
}
return ( 0x6 + ws ) < < 8 ;
}
2015-01-15 08:07:19 +00:00
int rsnd_adg_set_cmd_timsel_gen2 ( struct rsnd_mod * mod ,
2014-05-08 17:44:49 -07:00
struct rsnd_dai_stream * io )
{
2015-09-10 07:02:39 +00:00
struct rsnd_priv * priv = rsnd_mod_to_priv ( mod ) ;
struct rsnd_adg * adg = rsnd_priv_to_adg ( priv ) ;
struct rsnd_mod * adg_mod = rsnd_mod_get ( adg ) ;
2014-05-08 17:44:49 -07:00
int id = rsnd_mod_id ( mod ) ;
int shift = ( id % 2 ) ? 16 : 0 ;
u32 mask , val ;
val = rsnd_adg_ssi_ws_timing_gen2 ( io ) ;
val = val < < shift ;
mask = 0xffff < < shift ;
2015-09-10 07:02:39 +00:00
rsnd_mod_bset ( adg_mod , CMDOUT_TIMSEL , mask , val ) ;
2014-05-08 17:44:49 -07:00
return 0 ;
}
2015-09-10 07:03:08 +00:00
static int rsnd_adg_set_src_timsel_gen2 ( struct rsnd_mod * src_mod ,
2014-01-23 18:42:00 -08:00
struct rsnd_dai_stream * io ,
u32 timsel )
{
2015-09-10 07:03:08 +00:00
struct rsnd_priv * priv = rsnd_mod_to_priv ( src_mod ) ;
2015-09-10 07:02:39 +00:00
struct rsnd_adg * adg = rsnd_priv_to_adg ( priv ) ;
struct rsnd_mod * adg_mod = rsnd_mod_get ( adg ) ;
2015-01-15 08:06:49 +00:00
int is_play = rsnd_io_is_play ( io ) ;
2015-09-10 07:03:08 +00:00
int id = rsnd_mod_id ( src_mod ) ;
2014-01-23 18:42:00 -08:00
int shift = ( id % 2 ) ? 16 : 0 ;
u32 mask , ws ;
u32 in , out ;
2015-09-10 07:03:08 +00:00
rsnd_mod_confirm_src ( src_mod ) ;
2014-03-02 23:43:33 -08:00
ws = rsnd_adg_ssi_ws_timing_gen2 ( io ) ;
2014-01-23 18:42:00 -08:00
in = ( is_play ) ? timsel : ws ;
out = ( is_play ) ? ws : timsel ;
in = in < < shift ;
out = out < < shift ;
mask = 0xffff < < shift ;
switch ( id / 2 ) {
case 0 :
2015-09-10 07:02:39 +00:00
rsnd_mod_bset ( adg_mod , SRCIN_TIMSEL0 , mask , in ) ;
rsnd_mod_bset ( adg_mod , SRCOUT_TIMSEL0 , mask , out ) ;
2014-01-23 18:42:00 -08:00
break ;
case 1 :
2015-09-10 07:02:39 +00:00
rsnd_mod_bset ( adg_mod , SRCIN_TIMSEL1 , mask , in ) ;
rsnd_mod_bset ( adg_mod , SRCOUT_TIMSEL1 , mask , out ) ;
2014-01-23 18:42:00 -08:00
break ;
case 2 :
2015-09-10 07:02:39 +00:00
rsnd_mod_bset ( adg_mod , SRCIN_TIMSEL2 , mask , in ) ;
rsnd_mod_bset ( adg_mod , SRCOUT_TIMSEL2 , mask , out ) ;
2014-01-23 18:42:00 -08:00
break ;
case 3 :
2015-09-10 07:02:39 +00:00
rsnd_mod_bset ( adg_mod , SRCIN_TIMSEL3 , mask , in ) ;
rsnd_mod_bset ( adg_mod , SRCOUT_TIMSEL3 , mask , out ) ;
2014-01-23 18:42:00 -08:00
break ;
case 4 :
2015-09-10 07:02:39 +00:00
rsnd_mod_bset ( adg_mod , SRCIN_TIMSEL4 , mask , in ) ;
rsnd_mod_bset ( adg_mod , SRCOUT_TIMSEL4 , mask , out ) ;
2014-01-23 18:42:00 -08:00
break ;
}
return 0 ;
}
2015-09-10 07:03:08 +00:00
int rsnd_adg_set_convert_clk_gen2 ( struct rsnd_mod * src_mod ,
2014-01-23 18:42:00 -08:00
struct rsnd_dai_stream * io ,
unsigned int src_rate ,
unsigned int dst_rate )
{
2015-09-10 07:03:08 +00:00
struct rsnd_priv * priv = rsnd_mod_to_priv ( src_mod ) ;
2014-01-23 18:42:00 -08:00
struct rsnd_adg * adg = rsnd_priv_to_adg ( priv ) ;
2015-09-10 07:02:39 +00:00
struct rsnd_mod * adg_mod = rsnd_mod_get ( adg ) ;
2014-01-23 18:42:00 -08:00
struct device * dev = rsnd_priv_to_dev ( priv ) ;
2014-02-11 21:04:12 -08:00
int idx , sel , div , step , ret ;
u32 val , en ;
2014-01-23 18:42:00 -08:00
unsigned int min , diff ;
unsigned int sel_rate [ ] = {
clk_get_rate ( adg - > clk [ CLKA ] ) , /* 0000: CLKA */
clk_get_rate ( adg - > clk [ CLKB ] ) , /* 0001: CLKB */
clk_get_rate ( adg - > clk [ CLKC ] ) , /* 0010: CLKC */
2015-09-10 07:03:48 +00:00
adg - > rbga_rate_for_441khz , /* 0011: RBGA */
adg - > rbgb_rate_for_48khz , /* 0100: RBGB */
2014-01-23 18:42:00 -08:00
} ;
2015-09-10 07:03:08 +00:00
rsnd_mod_confirm_src ( src_mod ) ;
2014-01-23 18:42:00 -08:00
min = ~ 0 ;
val = 0 ;
2014-02-11 21:04:12 -08:00
en = 0 ;
2014-01-23 18:42:00 -08:00
for ( sel = 0 ; sel < ARRAY_SIZE ( sel_rate ) ; sel + + ) {
idx = 0 ;
step = 2 ;
if ( ! sel_rate [ sel ] )
continue ;
for ( div = 2 ; div < = 98304 ; div + = step ) {
diff = abs ( src_rate - sel_rate [ sel ] / div ) ;
if ( min > diff ) {
val = ( sel < < 8 ) | idx ;
min = diff ;
2014-02-11 21:04:12 -08:00
en = 1 < < ( sel + 1 ) ; /* fixme */
2014-01-23 18:42:00 -08:00
}
/*
* step of 0 _0000 / 0 _0001 / 0 _1101
* are out of order
*/
if ( ( idx > 2 ) & & ( idx % 2 ) )
step * = 2 ;
if ( idx = = 0x1c ) {
div + = step ;
step * = 2 ;
}
idx + + ;
}
}
if ( min = = ~ 0 ) {
dev_err ( dev , " no Input clock \n " ) ;
return - EIO ;
}
2015-09-10 07:03:08 +00:00
ret = rsnd_adg_set_src_timsel_gen2 ( src_mod , io , val ) ;
2014-02-11 21:04:12 -08:00
if ( ret < 0 ) {
dev_err ( dev , " timsel error \n " ) ;
return ret ;
}
2015-09-10 07:02:39 +00:00
rsnd_mod_bset ( adg_mod , DIV_EN , en , en ) ;
2014-02-11 21:04:12 -08:00
2015-03-19 04:14:45 +00:00
dev_dbg ( dev , " convert rate %d <-> %d \n " , src_rate , dst_rate ) ;
2014-02-11 21:04:12 -08:00
return 0 ;
2014-01-23 18:42:00 -08:00
}
2015-09-10 07:03:08 +00:00
int rsnd_adg_set_convert_timing_gen2 ( struct rsnd_mod * src_mod ,
2014-01-23 18:42:00 -08:00
struct rsnd_dai_stream * io )
{
2014-03-02 23:43:33 -08:00
u32 val = rsnd_adg_ssi_ws_timing_gen2 ( io ) ;
2014-01-23 18:42:00 -08:00
2015-09-10 07:03:08 +00:00
rsnd_mod_confirm_src ( src_mod ) ;
return rsnd_adg_set_src_timsel_gen2 ( src_mod , io , val ) ;
2014-01-23 18:42:00 -08:00
}
2014-01-23 18:41:10 -08:00
int rsnd_adg_set_convert_clk_gen1 ( struct rsnd_priv * priv ,
struct rsnd_mod * mod ,
unsigned int src_rate ,
unsigned int dst_rate )
2013-12-19 19:28:51 -08:00
{
struct rsnd_adg * adg = rsnd_priv_to_adg ( priv ) ;
2015-09-10 07:02:39 +00:00
struct rsnd_mod * adg_mod = rsnd_mod_get ( adg ) ;
2013-12-19 19:28:51 -08:00
struct device * dev = rsnd_priv_to_dev ( priv ) ;
int idx , sel , div , shift ;
u32 mask , val ;
int id = rsnd_mod_id ( mod ) ;
unsigned int sel_rate [ ] = {
clk_get_rate ( adg - > clk [ CLKA ] ) , /* 000: CLKA */
clk_get_rate ( adg - > clk [ CLKB ] ) , /* 001: CLKB */
clk_get_rate ( adg - > clk [ CLKC ] ) , /* 010: CLKC */
0 , /* 011: MLBCLK (not used) */
2015-09-10 07:03:48 +00:00
adg - > rbga_rate_for_441khz , /* 100: RBGA */
adg - > rbgb_rate_for_48khz , /* 101: RBGB */
2013-12-19 19:28:51 -08:00
} ;
/* find div (= 1/128, 1/256, 1/512, 1/1024, 1/2048 */
for ( sel = 0 ; sel < ARRAY_SIZE ( sel_rate ) ; sel + + ) {
for ( div = 128 , idx = 0 ;
div < = 2048 ;
div * = 2 , idx + + ) {
if ( src_rate = = sel_rate [ sel ] / div ) {
val = ( idx < < 4 ) | sel ;
goto find_rate ;
}
}
}
dev_err ( dev , " can't find convert src clk \n " ) ;
return - EINVAL ;
find_rate :
shift = ( id % 4 ) * 8 ;
mask = 0xFF < < shift ;
val = val < < shift ;
dev_dbg ( dev , " adg convert src clk = %02x \n " , val ) ;
switch ( id / 4 ) {
case 0 :
2015-09-10 07:02:39 +00:00
rsnd_mod_bset ( adg_mod , AUDIO_CLK_SEL3 , mask , val ) ;
2013-12-19 19:28:51 -08:00
break ;
case 1 :
2015-09-10 07:02:39 +00:00
rsnd_mod_bset ( adg_mod , AUDIO_CLK_SEL4 , mask , val ) ;
2013-12-19 19:28:51 -08:00
break ;
case 2 :
2015-09-10 07:02:39 +00:00
rsnd_mod_bset ( adg_mod , AUDIO_CLK_SEL5 , mask , val ) ;
2013-12-19 19:28:51 -08:00
break ;
}
/*
* Gen1 doesn ' t need dst_rate settings ,
* since it uses SSI WS pin .
* see also rsnd_src_set_route_if_gen1 ( )
*/
return 0 ;
}
2015-09-10 07:03:08 +00:00
static void rsnd_adg_set_ssi_clk ( struct rsnd_mod * ssi_mod , u32 val )
2013-07-21 21:36:46 -07:00
{
2015-09-10 07:03:08 +00:00
struct rsnd_priv * priv = rsnd_mod_to_priv ( ssi_mod ) ;
2015-09-10 07:02:39 +00:00
struct rsnd_adg * adg = rsnd_priv_to_adg ( priv ) ;
struct rsnd_mod * adg_mod = rsnd_mod_get ( adg ) ;
2015-09-10 07:03:08 +00:00
int id = rsnd_mod_id ( ssi_mod ) ;
2013-12-19 19:26:31 -08:00
int shift = ( id % 4 ) * 8 ;
u32 mask = 0xFF < < shift ;
2015-09-10 07:03:08 +00:00
rsnd_mod_confirm_ssi ( ssi_mod ) ;
2013-12-19 19:26:31 -08:00
val = val < < shift ;
2013-07-21 21:36:46 -07:00
/*
* SSI 8 is not connected to ADG .
* it works with SSI 7
*/
if ( id = = 8 )
2013-12-19 19:26:31 -08:00
return ;
switch ( id / 4 ) {
case 0 :
2015-09-10 07:02:39 +00:00
rsnd_mod_bset ( adg_mod , AUDIO_CLK_SEL0 , mask , val ) ;
2013-12-19 19:26:31 -08:00
break ;
case 1 :
2015-09-10 07:02:39 +00:00
rsnd_mod_bset ( adg_mod , AUDIO_CLK_SEL1 , mask , val ) ;
2013-12-19 19:26:31 -08:00
break ;
case 2 :
2015-09-10 07:02:39 +00:00
rsnd_mod_bset ( adg_mod , AUDIO_CLK_SEL2 , mask , val ) ;
2013-12-19 19:26:31 -08:00
break ;
}
2013-07-21 21:36:46 -07:00
}
int rsnd_adg_ssi_clk_stop ( struct rsnd_mod * mod )
{
/*
* " mod " = " ssi " here .
* we can get " ssi id " from mod
*/
2013-12-19 19:26:31 -08:00
rsnd_adg_set_ssi_clk ( mod , 0 ) ;
2013-07-21 21:36:46 -07:00
return 0 ;
}
int rsnd_adg_ssi_clk_try_start ( struct rsnd_mod * mod , unsigned int rate )
{
struct rsnd_priv * priv = rsnd_mod_to_priv ( mod ) ;
struct rsnd_adg * adg = rsnd_priv_to_adg ( priv ) ;
struct device * dev = rsnd_priv_to_dev ( priv ) ;
struct clk * clk ;
2013-12-19 19:26:31 -08:00
int i ;
2013-07-21 21:36:46 -07:00
u32 data ;
int sel_table [ ] = {
[ CLKA ] = 0x1 ,
[ CLKB ] = 0x2 ,
[ CLKC ] = 0x3 ,
[ CLKI ] = 0x0 ,
} ;
dev_dbg ( dev , " request clock = %d \n " , rate ) ;
/*
* find suitable clock from
* AUDIO_CLKA / AUDIO_CLKB / AUDIO_CLKC / AUDIO_CLKI .
*/
data = 0 ;
for_each_rsnd_clk ( clk , adg , i ) {
if ( rate = = clk_get_rate ( clk ) ) {
data = sel_table [ i ] ;
goto found_clock ;
}
}
/*
2015-09-10 07:03:48 +00:00
* find divided clock from BRGA / BRGB
2013-07-21 21:36:46 -07:00
*/
2015-09-10 07:03:48 +00:00
if ( rate = = adg - > rbga_rate_for_441khz ) {
2013-07-21 21:36:46 -07:00
data = 0x10 ;
goto found_clock ;
}
2015-09-10 07:03:48 +00:00
if ( rate = = adg - > rbgb_rate_for_48khz ) {
2013-07-21 21:36:46 -07:00
data = 0x20 ;
goto found_clock ;
}
return - EIO ;
found_clock :
/*
* This " mod " = " ssi " here .
* we can get " ssi id " from mod
*/
2013-12-19 19:26:31 -08:00
rsnd_adg_set_ssi_clk ( mod , data ) ;
2013-07-21 21:36:46 -07:00
2015-09-10 07:04:06 +00:00
dev_dbg ( dev , " ADG: %s[%d] selects 0x%x for %d \n " ,
rsnd_mod_name ( mod ) , rsnd_mod_id ( mod ) ,
data , rate ) ;
2013-07-21 21:36:46 -07:00
return 0 ;
}
static void rsnd_adg_ssi_clk_init ( struct rsnd_priv * priv , struct rsnd_adg * adg )
{
struct clk * clk ;
2015-09-10 07:03:25 +00:00
struct rsnd_mod * adg_mod = rsnd_mod_get ( adg ) ;
2015-09-10 07:03:48 +00:00
struct device * dev = rsnd_priv_to_dev ( priv ) ;
unsigned long rate , div ;
u32 ckr , rbgx , rbga , rbgb ;
2013-07-21 21:36:46 -07:00
int i ;
int brg_table [ ] = {
[ CLKA ] = 0x0 ,
[ CLKB ] = 0x1 ,
[ CLKC ] = 0x4 ,
[ CLKI ] = 0x2 ,
} ;
/*
* This driver is assuming that AUDIO_CLKA / AUDIO_CLKB / AUDIO_CLKC
* have 44.1 kHz or 48 kHz base clocks for now .
*
* SSI itself can divide parent clock by 1 / 1 - 1 / 16
* see
* rsnd_adg_ssi_clk_try_start ( )
2015-09-10 07:03:25 +00:00
* rsnd_ssi_master_clk_start ( )
2013-07-21 21:36:46 -07:00
*/
ckr = 0 ;
2015-09-10 07:03:48 +00:00
rbga = 2 ; /* default 1/6 */
rbgb = 2 ; /* default 1/6 */
adg - > rbga_rate_for_441khz = 0 ;
adg - > rbgb_rate_for_48khz = 0 ;
2013-07-21 21:36:46 -07:00
for_each_rsnd_clk ( clk , adg , i ) {
rate = clk_get_rate ( clk ) ;
if ( 0 = = rate ) /* not used */
continue ;
/* RBGA */
2015-09-10 07:03:48 +00:00
if ( ! adg - > rbga_rate_for_441khz & & ( 0 = = rate % 44100 ) ) {
div = 6 ;
rbgx = rsnd_adg_calculate_rbgx ( div ) ;
if ( BRRx_MASK ( rbgx ) = = rbgx ) {
rbga = rbgx ;
adg - > rbga_rate_for_441khz = rate / div ;
ckr | = brg_table [ i ] < < 20 ;
}
2013-07-21 21:36:46 -07:00
}
/* RBGB */
2015-09-10 07:03:48 +00:00
if ( ! adg - > rbgb_rate_for_48khz & & ( 0 = = rate % 48000 ) ) {
div = 6 ;
rbgx = rsnd_adg_calculate_rbgx ( div ) ;
if ( BRRx_MASK ( rbgx ) = = rbgx ) {
rbgb = rbgx ;
adg - > rbgb_rate_for_48khz = rate / div ;
ckr | = brg_table [ i ] < < 16 ;
}
2013-07-21 21:36:46 -07:00
}
}
2015-09-10 07:03:25 +00:00
rsnd_mod_bset ( adg_mod , SSICKR , 0x00FF0000 , ckr ) ;
2015-09-10 07:03:48 +00:00
rsnd_mod_write ( adg_mod , BRRA , rbga ) ;
rsnd_mod_write ( adg_mod , BRRB , rbgb ) ;
dev_dbg ( dev , " SSICKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x \n " ,
ckr , rbga , rbgb ) ;
2013-07-21 21:36:46 -07:00
}
int rsnd_adg_probe ( struct platform_device * pdev ,
2014-03-17 19:29:55 -07:00
const struct rsnd_of_data * of_data ,
2013-07-21 21:36:46 -07:00
struct rsnd_priv * priv )
{
struct rsnd_adg * adg ;
struct device * dev = rsnd_priv_to_dev ( priv ) ;
2014-05-08 01:59:00 -07:00
struct clk * clk ;
2013-07-21 21:36:46 -07:00
int i ;
adg = devm_kzalloc ( dev , sizeof ( * adg ) , GFP_KERNEL ) ;
if ( ! adg ) {
dev_err ( dev , " ADG allocate failed \n " ) ;
return - ENOMEM ;
}
2015-09-10 07:02:39 +00:00
/*
* ADG is special module .
* Use ADG mod without rsnd_mod_init ( ) to make debug easy
* for rsnd_write / rsnd_read
*/
adg - > mod . ops = & adg_ops ;
adg - > mod . priv = priv ;
2014-03-02 23:43:11 -08:00
adg - > clk [ CLKA ] = devm_clk_get ( dev , " clk_a " ) ;
adg - > clk [ CLKB ] = devm_clk_get ( dev , " clk_b " ) ;
adg - > clk [ CLKC ] = devm_clk_get ( dev , " clk_c " ) ;
adg - > clk [ CLKI ] = devm_clk_get ( dev , " clk_i " ) ;
2014-02-07 00:53:06 -08:00
2014-05-08 01:59:00 -07:00
for_each_rsnd_clk ( clk , adg , i )
2014-11-27 08:06:03 +00:00
dev_dbg ( dev , " clk %d : %p : %ld \n " , i , clk , clk_get_rate ( clk ) ) ;
2013-07-21 21:36:46 -07:00
rsnd_adg_ssi_clk_init ( priv , adg ) ;
priv - > adg = adg ;
return 0 ;
}