2018-09-07 19:58:49 +03:00
// SPDX-License-Identifier: GPL-2.0
/*
* R7S9210 Clock Pulse Generator / Module Standby
*
* Based on r8a7795 - cpg - mssr . c
*
* Copyright ( C ) 2018 Chris Brandt
* Copyright ( C ) 2018 Renesas Electronics Corp .
*
*/
# include <linux/clk.h>
# include <linux/clk-provider.h>
2019-03-12 11:02:52 +03:00
# include <linux/io.h>
2018-09-07 19:58:49 +03:00
# include <dt-bindings/clock/r7s9210-cpg-mssr.h>
# include "renesas-cpg-mssr.h"
# define CPG_FRQCR 0x00
static u8 cpg_mode ;
/* Internal Clock ratio table */
static const struct {
unsigned int i ;
unsigned int g ;
unsigned int b ;
unsigned int p1 ;
/* p0 is always 32 */ ;
} ratio_tab [ 5 ] = { /* I, G, B, P1 */
{ 2 , 4 , 8 , 16 } , /* FRQCR = 0x012 */
{ 4 , 4 , 8 , 16 } , /* FRQCR = 0x112 */
{ 8 , 4 , 8 , 16 } , /* FRQCR = 0x212 */
{ 16 , 8 , 16 , 16 } , /* FRQCR = 0x322 */
{ 16 , 16 , 32 , 32 } , /* FRQCR = 0x333 */
} ;
enum rz_clk_types {
CLK_TYPE_RZA_MAIN = CLK_TYPE_CUSTOM ,
CLK_TYPE_RZA_PLL ,
} ;
enum clk_ids {
/* Core Clock Outputs exported to DT */
LAST_DT_CORE_CLK = R7S9210_CLK_P0 ,
/* External Input Clocks */
CLK_EXTAL ,
/* Internal Core Clocks */
CLK_MAIN ,
CLK_PLL ,
/* Module Clocks */
MOD_CLK_BASE
} ;
2018-09-24 19:49:36 +03:00
static struct cpg_core_clk r7s9210_early_core_clks [ ] = {
2018-09-07 19:58:49 +03:00
/* External Clock Inputs */
DEF_INPUT ( " extal " , CLK_EXTAL ) ,
/* Internal Core Clocks */
DEF_BASE ( " .main " , CLK_MAIN , CLK_TYPE_RZA_MAIN , CLK_EXTAL ) ,
DEF_BASE ( " .pll " , CLK_PLL , CLK_TYPE_RZA_PLL , CLK_MAIN ) ,
2018-09-24 19:49:36 +03:00
/* Core Clock Outputs */
DEF_FIXED ( " p1c " , R7S9210_CLK_P1C , CLK_PLL , 16 , 1 ) ,
} ;
static const struct mssr_mod_clk r7s9210_early_mod_clks [ ] __initconst = {
DEF_MOD_STB ( " ostm2 " , 34 , R7S9210_CLK_P1C ) ,
DEF_MOD_STB ( " ostm1 " , 35 , R7S9210_CLK_P1C ) ,
DEF_MOD_STB ( " ostm0 " , 36 , R7S9210_CLK_P1C ) ,
} ;
static struct cpg_core_clk r7s9210_core_clks [ ] = {
2018-09-07 19:58:49 +03:00
/* Core Clock Outputs */
DEF_FIXED ( " i " , R7S9210_CLK_I , CLK_PLL , 2 , 1 ) ,
DEF_FIXED ( " g " , R7S9210_CLK_G , CLK_PLL , 4 , 1 ) ,
DEF_FIXED ( " b " , R7S9210_CLK_B , CLK_PLL , 8 , 1 ) ,
DEF_FIXED ( " p1 " , R7S9210_CLK_P1 , CLK_PLL , 16 , 1 ) ,
DEF_FIXED ( " p0 " , R7S9210_CLK_P0 , CLK_PLL , 32 , 1 ) ,
} ;
static const struct mssr_mod_clk r7s9210_mod_clks [ ] __initconst = {
DEF_MOD_STB ( " scif4 " , 43 , R7S9210_CLK_P1C ) ,
DEF_MOD_STB ( " scif3 " , 44 , R7S9210_CLK_P1C ) ,
DEF_MOD_STB ( " scif2 " , 45 , R7S9210_CLK_P1C ) ,
DEF_MOD_STB ( " scif1 " , 46 , R7S9210_CLK_P1C ) ,
DEF_MOD_STB ( " scif0 " , 47 , R7S9210_CLK_P1C ) ,
2018-11-07 20:35:56 +03:00
DEF_MOD_STB ( " usb1 " , 60 , R7S9210_CLK_B ) ,
DEF_MOD_STB ( " usb0 " , 61 , R7S9210_CLK_B ) ,
2018-09-07 19:58:49 +03:00
DEF_MOD_STB ( " ether1 " , 64 , R7S9210_CLK_B ) ,
DEF_MOD_STB ( " ether0 " , 65 , R7S9210_CLK_B ) ,
2019-12-06 16:41:59 +03:00
DEF_MOD_STB ( " spibsc " , 83 , R7S9210_CLK_P1 ) ,
2018-09-07 19:58:49 +03:00
DEF_MOD_STB ( " i2c3 " , 84 , R7S9210_CLK_P1 ) ,
DEF_MOD_STB ( " i2c2 " , 85 , R7S9210_CLK_P1 ) ,
DEF_MOD_STB ( " i2c1 " , 86 , R7S9210_CLK_P1 ) ,
DEF_MOD_STB ( " i2c0 " , 87 , R7S9210_CLK_P1 ) ,
2018-09-26 16:39:56 +03:00
DEF_MOD_STB ( " spi2 " , 95 , R7S9210_CLK_P1 ) ,
DEF_MOD_STB ( " spi1 " , 96 , R7S9210_CLK_P1 ) ,
DEF_MOD_STB ( " spi0 " , 97 , R7S9210_CLK_P1 ) ,
2018-10-08 19:23:47 +03:00
DEF_MOD_STB ( " sdhi11 " , 100 , R7S9210_CLK_B ) ,
DEF_MOD_STB ( " sdhi10 " , 101 , R7S9210_CLK_B ) ,
DEF_MOD_STB ( " sdhi01 " , 102 , R7S9210_CLK_B ) ,
DEF_MOD_STB ( " sdhi00 " , 103 , R7S9210_CLK_B ) ,
2018-09-07 19:58:49 +03:00
} ;
2018-09-24 19:49:37 +03:00
/* The clock dividers in the table vary based on DT and register settings */
static void __init r7s9210_update_clk_table ( struct clk * extal_clk ,
void __iomem * base )
{
int i ;
u16 frqcr ;
u8 index ;
/* If EXTAL is above 12MHz, then we know it is Mode 1 */
if ( clk_get_rate ( extal_clk ) > 12000000 )
cpg_mode = 1 ;
2019-03-12 11:02:52 +03:00
frqcr = readl ( base + CPG_FRQCR ) & 0xFFF ;
2018-09-24 19:49:37 +03:00
if ( frqcr = = 0x012 )
index = 0 ;
else if ( frqcr = = 0x112 )
index = 1 ;
else if ( frqcr = = 0x212 )
index = 2 ;
else if ( frqcr = = 0x322 )
index = 3 ;
else if ( frqcr = = 0x333 )
index = 4 ;
else
BUG_ON ( 1 ) ; /* Illegal FRQCR value */
for ( i = 0 ; i < ARRAY_SIZE ( r7s9210_core_clks ) ; i + + ) {
switch ( r7s9210_core_clks [ i ] . id ) {
case R7S9210_CLK_I :
r7s9210_core_clks [ i ] . div = ratio_tab [ index ] . i ;
break ;
case R7S9210_CLK_G :
r7s9210_core_clks [ i ] . div = ratio_tab [ index ] . g ;
break ;
case R7S9210_CLK_B :
r7s9210_core_clks [ i ] . div = ratio_tab [ index ] . b ;
break ;
case R7S9210_CLK_P1 :
case R7S9210_CLK_P1C :
r7s9210_core_clks [ i ] . div = ratio_tab [ index ] . p1 ;
break ;
case R7S9210_CLK_P0 :
r7s9210_core_clks [ i ] . div = 32 ;
break ;
}
}
}
2018-11-28 21:37:02 +03:00
static struct clk * __init rza2_cpg_clk_register ( struct device * dev ,
2018-09-07 19:58:49 +03:00
const struct cpg_core_clk * core , const struct cpg_mssr_info * info ,
struct clk * * clks , void __iomem * base ,
struct raw_notifier_head * notifiers )
{
struct clk * parent ;
unsigned int mult = 1 ;
unsigned int div = 1 ;
parent = clks [ core - > parent ] ;
if ( IS_ERR ( parent ) )
return ERR_CAST ( parent ) ;
switch ( core - > id ) {
case CLK_MAIN :
break ;
case CLK_PLL :
if ( cpg_mode )
mult = 44 ; /* Divider 1 is 1/2 */
else
mult = 88 ; /* Divider 1 is 1 */
break ;
default :
return ERR_PTR ( - EINVAL ) ;
}
2018-09-24 19:49:37 +03:00
if ( core - > id = = CLK_MAIN )
r7s9210_update_clk_table ( parent , base ) ;
2018-09-07 19:58:49 +03:00
return clk_register_fixed_factor ( NULL , core - > name ,
__clk_get_name ( parent ) , 0 , mult , div ) ;
}
const struct cpg_mssr_info r7s9210_cpg_mssr_info __initconst = {
2018-09-24 19:49:36 +03:00
/* Early Clocks */
. early_core_clks = r7s9210_early_core_clks ,
. num_early_core_clks = ARRAY_SIZE ( r7s9210_early_core_clks ) ,
. early_mod_clks = r7s9210_early_mod_clks ,
. num_early_mod_clks = ARRAY_SIZE ( r7s9210_early_mod_clks ) ,
2018-09-07 19:58:49 +03:00
/* Core Clocks */
. core_clks = r7s9210_core_clks ,
. num_core_clks = ARRAY_SIZE ( r7s9210_core_clks ) ,
. last_dt_core_clk = LAST_DT_CORE_CLK ,
. num_total_core_clks = MOD_CLK_BASE ,
/* Module Clocks */
. mod_clks = r7s9210_mod_clks ,
. num_mod_clks = ARRAY_SIZE ( r7s9210_mod_clks ) ,
. num_hw_mod_clks = 11 * 32 , /* includes STBCR0 which doesn't exist */
/* Callbacks */
. cpg_clk_register = rza2_cpg_clk_register ,
/* RZ/A2 has Standby Control Registers */
2020-09-11 10:43:49 +03:00
. reg_layout = CLK_REG_LAYOUT_RZ_A ,
2018-09-07 19:58:49 +03:00
} ;
2018-09-24 19:49:36 +03:00
static void __init r7s9210_cpg_mssr_early_init ( struct device_node * np )
{
cpg_mssr_early_init ( np , & r7s9210_cpg_mssr_info ) ;
}
CLK_OF_DECLARE_DRIVER ( cpg_mstp_clks , " renesas,r7s9210-cpg-mssr " ,
r7s9210_cpg_mssr_early_init ) ;