2018-08-22 00:02:14 +02:00
// SPDX-License-Identifier: GPL-2.0
2016-05-04 14:32:56 +02:00
/*
* R - Car Gen3 Clock Pulse Generator
*
2018-07-11 13:54:30 +02:00
* Copyright ( C ) 2015 - 2018 Glider bvba
2016-05-04 14:32:56 +02:00
*
* Based on clk - rcar - gen3 . c
*
* Copyright ( C ) 2015 Renesas Electronics Corp .
*/
# include <linux/bug.h>
2018-01-29 19:01:49 +01:00
# include <linux/bitfield.h>
2016-05-04 14:32:56 +02:00
# include <linux/clk.h>
# include <linux/clk-provider.h>
# include <linux/device.h>
# include <linux/err.h>
# include <linux/init.h>
# include <linux/io.h>
2017-06-21 22:51:21 +02:00
# include <linux/pm.h>
2016-05-04 14:32:56 +02:00
# include <linux/slab.h>
2017-03-10 11:46:10 +01:00
# include <linux/sys_soc.h>
2016-05-04 14:32:56 +02:00
# include "renesas-cpg-mssr.h"
# include "rcar-gen3-cpg.h"
# define CPG_PLL0CR 0x00d8
# define CPG_PLL2CR 0x002c
# define CPG_PLL4CR 0x01f4
2018-07-11 13:54:30 +02:00
# define CPG_RCKCR_CKSEL BIT(15) /* RCLK Clock Source Select */
2017-06-21 22:51:21 +02:00
struct cpg_simple_notifier {
struct notifier_block nb ;
void __iomem * reg ;
u32 saved ;
} ;
static int cpg_simple_notifier_call ( struct notifier_block * nb ,
unsigned long action , void * data )
{
struct cpg_simple_notifier * csn =
container_of ( nb , struct cpg_simple_notifier , nb ) ;
switch ( action ) {
case PM_EVENT_SUSPEND :
csn - > saved = readl ( csn - > reg ) ;
return NOTIFY_OK ;
case PM_EVENT_RESUME :
writel ( csn - > saved , csn - > reg ) ;
return NOTIFY_OK ;
}
return NOTIFY_DONE ;
}
static void cpg_simple_notifier_register ( struct raw_notifier_head * notifiers ,
struct cpg_simple_notifier * csn )
{
csn - > nb . notifier_call = cpg_simple_notifier_call ;
raw_notifier_chain_register ( notifiers , & csn - > nb ) ;
}
2016-05-04 14:32:56 +02:00
2018-01-29 19:01:49 +01:00
/*
2018-01-29 19:01:50 +01:00
* Z Clock & Z2 Clock
2018-01-29 19:01:49 +01:00
*
* Traits of this clock :
* prepare - clk_prepare only ensures that parents are prepared
* enable - clk_enable only ensures that parents are enabled
* rate - rate is adjustable . clk - > rate = ( parent - > rate * mult / 32 ) / 2
* parent - fixed parent . No clk_set_parent support
*/
# define CPG_FRQCRB 0x00000004
# define CPG_FRQCRB_KICK BIT(31)
# define CPG_FRQCRC 0x000000e0
# define CPG_FRQCRC_ZFC_MASK GENMASK(12, 8)
2018-01-29 19:01:50 +01:00
# define CPG_FRQCRC_Z2FC_MASK GENMASK(4, 0)
2018-01-29 19:01:49 +01:00
struct cpg_z_clk {
struct clk_hw hw ;
void __iomem * reg ;
void __iomem * kick_reg ;
2018-01-29 19:01:50 +01:00
unsigned long mask ;
2018-01-29 19:01:49 +01:00
} ;
# define to_z_clk(_hw) container_of(_hw, struct cpg_z_clk, hw)
static unsigned long cpg_z_clk_recalc_rate ( struct clk_hw * hw ,
unsigned long parent_rate )
{
struct cpg_z_clk * zclk = to_z_clk ( hw ) ;
unsigned int mult ;
2018-01-29 19:01:50 +01:00
u32 val ;
2018-01-29 19:01:49 +01:00
2018-03-15 10:44:37 +01:00
val = readl ( zclk - > reg ) & zclk - > mask ;
2018-01-29 19:01:50 +01:00
mult = 32 - ( val > > __ffs ( zclk - > mask ) ) ;
2018-01-29 19:01:49 +01:00
/* Factor of 2 is for fixed divider */
return DIV_ROUND_CLOSEST_ULL ( ( u64 ) parent_rate * mult , 32 * 2 ) ;
}
static long cpg_z_clk_round_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long * parent_rate )
{
/* Factor of 2 is for fixed divider */
unsigned long prate = * parent_rate / 2 ;
unsigned int mult ;
mult = div_u64 ( rate * 32ULL , prate ) ;
mult = clamp ( mult , 1U , 32U ) ;
return ( u64 ) prate * mult / 32 ;
}
static int cpg_z_clk_set_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long parent_rate )
{
struct cpg_z_clk * zclk = to_z_clk ( hw ) ;
unsigned int mult ;
unsigned int i ;
u32 val , kick ;
/* Factor of 2 is for fixed divider */
mult = DIV_ROUND_CLOSEST_ULL ( rate * 32ULL * 2 , parent_rate ) ;
mult = clamp ( mult , 1U , 32U ) ;
2018-03-15 10:44:37 +01:00
if ( readl ( zclk - > kick_reg ) & CPG_FRQCRB_KICK )
2018-01-29 19:01:49 +01:00
return - EBUSY ;
2018-03-15 10:44:37 +01:00
val = readl ( zclk - > reg ) & ~ zclk - > mask ;
2018-01-29 19:01:50 +01:00
val | = ( ( 32 - mult ) < < __ffs ( zclk - > mask ) ) & zclk - > mask ;
2018-03-15 10:44:37 +01:00
writel ( val , zclk - > reg ) ;
2018-01-29 19:01:49 +01:00
/*
* Set KICK bit in FRQCRB to update hardware setting and wait for
* clock change completion .
*/
2018-03-15 10:44:37 +01:00
kick = readl ( zclk - > kick_reg ) ;
2018-01-29 19:01:49 +01:00
kick | = CPG_FRQCRB_KICK ;
2018-03-15 10:44:37 +01:00
writel ( kick , zclk - > kick_reg ) ;
2018-01-29 19:01:49 +01:00
/*
* Note : There is no HW information about the worst case latency .
*
* Using experimental measurements , it seems that no more than
* ~ 10 iterations are needed , independently of the CPU rate .
* Since this value might be dependent of external xtal rate , pll1
* rate or even the other emulation clocks rate , use 1000 as a
* " super " safe value .
*/
for ( i = 1000 ; i ; i - - ) {
2018-03-15 10:44:37 +01:00
if ( ! ( readl ( zclk - > kick_reg ) & CPG_FRQCRB_KICK ) )
2018-01-29 19:01:49 +01:00
return 0 ;
cpu_relax ( ) ;
}
return - ETIMEDOUT ;
}
static const struct clk_ops cpg_z_clk_ops = {
. recalc_rate = cpg_z_clk_recalc_rate ,
. round_rate = cpg_z_clk_round_rate ,
. set_rate = cpg_z_clk_set_rate ,
} ;
static struct clk * __init cpg_z_clk_register ( const char * name ,
const char * parent_name ,
2018-01-29 19:01:50 +01:00
void __iomem * reg ,
unsigned long mask )
2018-01-29 19:01:49 +01:00
{
struct clk_init_data init ;
struct cpg_z_clk * zclk ;
struct clk * clk ;
zclk = kzalloc ( sizeof ( * zclk ) , GFP_KERNEL ) ;
if ( ! zclk )
return ERR_PTR ( - ENOMEM ) ;
init . name = name ;
init . ops = & cpg_z_clk_ops ;
init . flags = 0 ;
init . parent_names = & parent_name ;
init . num_parents = 1 ;
zclk - > reg = reg + CPG_FRQCRC ;
zclk - > kick_reg = reg + CPG_FRQCRB ;
zclk - > hw . init = & init ;
2018-01-29 19:01:50 +01:00
zclk - > mask = mask ;
2018-01-29 19:01:49 +01:00
clk = clk_register ( NULL , & zclk - > hw ) ;
if ( IS_ERR ( clk ) )
kfree ( zclk ) ;
return clk ;
}
2016-05-04 14:32:56 +02:00
/*
* SDn Clock
*/
# define CPG_SD_STP_HCK BIT(9)
# define CPG_SD_STP_CK BIT(8)
# define CPG_SD_STP_MASK (CPG_SD_STP_HCK | CPG_SD_STP_CK)
# define CPG_SD_FC_MASK (0x7 << 2 | 0x3 << 0)
# define CPG_SD_DIV_TABLE_DATA(stp_hck, stp_ck, sd_srcfc, sd_fc, sd_div) \
{ \
. val = ( ( stp_hck ) ? CPG_SD_STP_HCK : 0 ) | \
( ( stp_ck ) ? CPG_SD_STP_CK : 0 ) | \
( ( sd_srcfc ) < < 2 ) | \
( ( sd_fc ) < < 0 ) , \
. div = ( sd_div ) , \
}
struct sd_div_table {
u32 val ;
unsigned int div ;
} ;
struct sd_clock {
struct clk_hw hw ;
const struct sd_div_table * div_table ;
2017-06-21 22:51:21 +02:00
struct cpg_simple_notifier csn ;
2016-05-04 14:32:56 +02:00
unsigned int div_num ;
unsigned int div_min ;
unsigned int div_max ;
2017-07-18 18:44:07 +02:00
unsigned int cur_div_idx ;
2016-05-04 14:32:56 +02:00
} ;
/* SDn divider
* sd_srcfc sd_fc div
* stp_hck stp_ck ( div ) ( div ) = sd_srcfc x sd_fc
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* 0 0 0 ( 1 ) 1 ( 4 ) 4
* 0 0 1 ( 2 ) 1 ( 4 ) 8
* 1 0 2 ( 4 ) 1 ( 4 ) 16
* 1 0 3 ( 8 ) 1 ( 4 ) 32
* 1 0 4 ( 16 ) 1 ( 4 ) 64
* 0 0 0 ( 1 ) 0 ( 2 ) 2
* 0 0 1 ( 2 ) 0 ( 2 ) 4
* 1 0 2 ( 4 ) 0 ( 2 ) 8
* 1 0 3 ( 8 ) 0 ( 2 ) 16
* 1 0 4 ( 16 ) 0 ( 2 ) 32
*/
static const struct sd_div_table cpg_sd_div_table [ ] = {
/* CPG_SD_DIV_TABLE_DATA(stp_hck, stp_ck, sd_srcfc, sd_fc, sd_div) */
CPG_SD_DIV_TABLE_DATA ( 0 , 0 , 0 , 1 , 4 ) ,
CPG_SD_DIV_TABLE_DATA ( 0 , 0 , 1 , 1 , 8 ) ,
CPG_SD_DIV_TABLE_DATA ( 1 , 0 , 2 , 1 , 16 ) ,
CPG_SD_DIV_TABLE_DATA ( 1 , 0 , 3 , 1 , 32 ) ,
CPG_SD_DIV_TABLE_DATA ( 1 , 0 , 4 , 1 , 64 ) ,
CPG_SD_DIV_TABLE_DATA ( 0 , 0 , 0 , 0 , 2 ) ,
CPG_SD_DIV_TABLE_DATA ( 0 , 0 , 1 , 0 , 4 ) ,
CPG_SD_DIV_TABLE_DATA ( 1 , 0 , 2 , 0 , 8 ) ,
CPG_SD_DIV_TABLE_DATA ( 1 , 0 , 3 , 0 , 16 ) ,
CPG_SD_DIV_TABLE_DATA ( 1 , 0 , 4 , 0 , 32 ) ,
} ;
# define to_sd_clock(_hw) container_of(_hw, struct sd_clock, hw)
static int cpg_sd_clock_enable ( struct clk_hw * hw )
{
struct sd_clock * clock = to_sd_clock ( hw ) ;
2017-06-21 22:51:21 +02:00
u32 val = readl ( clock - > csn . reg ) ;
2016-05-04 14:32:56 +02:00
val & = ~ ( CPG_SD_STP_MASK ) ;
2017-07-18 18:44:07 +02:00
val | = clock - > div_table [ clock - > cur_div_idx ] . val & CPG_SD_STP_MASK ;
2016-05-04 14:32:56 +02:00
2017-06-21 22:51:21 +02:00
writel ( val , clock - > csn . reg ) ;
2016-05-04 14:32:56 +02:00
return 0 ;
}
static void cpg_sd_clock_disable ( struct clk_hw * hw )
{
struct sd_clock * clock = to_sd_clock ( hw ) ;
2017-06-21 22:51:21 +02:00
writel ( readl ( clock - > csn . reg ) | CPG_SD_STP_MASK , clock - > csn . reg ) ;
2016-05-04 14:32:56 +02:00
}
static int cpg_sd_clock_is_enabled ( struct clk_hw * hw )
{
struct sd_clock * clock = to_sd_clock ( hw ) ;
2017-06-21 22:51:21 +02:00
return ! ( readl ( clock - > csn . reg ) & CPG_SD_STP_MASK ) ;
2016-05-04 14:32:56 +02:00
}
static unsigned long cpg_sd_clock_recalc_rate ( struct clk_hw * hw ,
unsigned long parent_rate )
{
struct sd_clock * clock = to_sd_clock ( hw ) ;
2017-07-18 18:44:07 +02:00
return DIV_ROUND_CLOSEST ( parent_rate ,
clock - > div_table [ clock - > cur_div_idx ] . div ) ;
2016-05-04 14:32:56 +02:00
}
static unsigned int cpg_sd_clock_calc_div ( struct sd_clock * clock ,
unsigned long rate ,
unsigned long parent_rate )
{
unsigned int div ;
if ( ! rate )
rate = 1 ;
div = DIV_ROUND_CLOSEST ( parent_rate , rate ) ;
return clamp_t ( unsigned int , div , clock - > div_min , clock - > div_max ) ;
}
static long cpg_sd_clock_round_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long * parent_rate )
{
struct sd_clock * clock = to_sd_clock ( hw ) ;
unsigned int div = cpg_sd_clock_calc_div ( clock , rate , * parent_rate ) ;
return DIV_ROUND_CLOSEST ( * parent_rate , div ) ;
}
static int cpg_sd_clock_set_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long parent_rate )
{
struct sd_clock * clock = to_sd_clock ( hw ) ;
unsigned int div = cpg_sd_clock_calc_div ( clock , rate , parent_rate ) ;
u32 val ;
unsigned int i ;
for ( i = 0 ; i < clock - > div_num ; i + + )
if ( div = = clock - > div_table [ i ] . div )
break ;
if ( i > = clock - > div_num )
return - EINVAL ;
2017-07-18 18:44:07 +02:00
clock - > cur_div_idx = i ;
2017-06-21 22:51:21 +02:00
val = readl ( clock - > csn . reg ) ;
2016-05-04 14:32:56 +02:00
val & = ~ ( CPG_SD_STP_MASK | CPG_SD_FC_MASK ) ;
val | = clock - > div_table [ i ] . val & ( CPG_SD_STP_MASK | CPG_SD_FC_MASK ) ;
2017-06-21 22:51:21 +02:00
writel ( val , clock - > csn . reg ) ;
2016-05-04 14:32:56 +02:00
return 0 ;
}
static const struct clk_ops cpg_sd_clock_ops = {
. enable = cpg_sd_clock_enable ,
. disable = cpg_sd_clock_disable ,
. is_enabled = cpg_sd_clock_is_enabled ,
. recalc_rate = cpg_sd_clock_recalc_rate ,
. round_rate = cpg_sd_clock_round_rate ,
. set_rate = cpg_sd_clock_set_rate ,
} ;
static struct clk * __init cpg_sd_clk_register ( const struct cpg_core_clk * core ,
2017-06-21 22:51:21 +02:00
void __iomem * base , const char * parent_name ,
struct raw_notifier_head * notifiers )
2016-05-04 14:32:56 +02:00
{
struct clk_init_data init ;
struct sd_clock * clock ;
struct clk * clk ;
unsigned int i ;
2017-07-18 18:44:07 +02:00
u32 sd_fc ;
2016-05-04 14:32:56 +02:00
clock = kzalloc ( sizeof ( * clock ) , GFP_KERNEL ) ;
if ( ! clock )
return ERR_PTR ( - ENOMEM ) ;
init . name = core - > name ;
init . ops = & cpg_sd_clock_ops ;
init . flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT ;
init . parent_names = & parent_name ;
init . num_parents = 1 ;
2017-06-21 22:51:21 +02:00
clock - > csn . reg = base + core - > offset ;
2016-05-04 14:32:56 +02:00
clock - > hw . init = & init ;
clock - > div_table = cpg_sd_div_table ;
clock - > div_num = ARRAY_SIZE ( cpg_sd_div_table ) ;
2017-06-21 22:51:21 +02:00
sd_fc = readl ( clock - > csn . reg ) & CPG_SD_FC_MASK ;
2017-07-18 18:44:07 +02:00
for ( i = 0 ; i < clock - > div_num ; i + + )
if ( sd_fc = = ( clock - > div_table [ i ] . val & CPG_SD_FC_MASK ) )
break ;
if ( WARN_ON ( i > = clock - > div_num ) ) {
kfree ( clock ) ;
return ERR_PTR ( - EINVAL ) ;
}
clock - > cur_div_idx = i ;
2016-05-04 14:32:56 +02:00
clock - > div_max = clock - > div_table [ 0 ] . div ;
clock - > div_min = clock - > div_max ;
for ( i = 1 ; i < clock - > div_num ; i + + ) {
clock - > div_max = max ( clock - > div_max , clock - > div_table [ i ] . div ) ;
clock - > div_min = min ( clock - > div_min , clock - > div_table [ i ] . div ) ;
}
clk = clk_register ( NULL , & clock - > hw ) ;
if ( IS_ERR ( clk ) )
2017-06-21 22:51:21 +02:00
goto free_clock ;
cpg_simple_notifier_register ( notifiers , & clock - > csn ) ;
return clk ;
2016-05-04 14:32:56 +02:00
2017-06-21 22:51:21 +02:00
free_clock :
kfree ( clock ) ;
2016-05-04 14:32:56 +02:00
return clk ;
}
static const struct rcar_gen3_cpg_pll_config * cpg_pll_config __initdata ;
static unsigned int cpg_clk_extalr __initdata ;
2017-03-10 11:36:33 +01:00
static u32 cpg_mode __initdata ;
2017-03-10 11:46:10 +01:00
static u32 cpg_quirks __initdata ;
# define PLL_ERRATA BIT(0) /* Missing PLL0/2/4 post-divider */
2017-03-10 12:13:37 +01:00
# define RCKCR_CKSEL BIT(1) /* Manual RCLK parent selection */
2017-03-10 11:46:10 +01:00
static const struct soc_device_attribute cpg_quirks_match [ ] __initconst = {
{
. soc_id = " r8a7795 " , . revision = " ES1.0 " ,
2017-03-10 12:13:37 +01:00
. data = ( void * ) ( PLL_ERRATA | RCKCR_CKSEL ) ,
} ,
{
. soc_id = " r8a7795 " , . revision = " ES1.* " ,
. data = ( void * ) RCKCR_CKSEL ,
} ,
{
. soc_id = " r8a7796 " , . revision = " ES1.0 " ,
. data = ( void * ) RCKCR_CKSEL ,
2017-03-10 11:46:10 +01:00
} ,
{ /* sentinel */ }
} ;
2016-05-04 14:32:56 +02:00
struct clk * __init rcar_gen3_cpg_clk_register ( struct device * dev ,
const struct cpg_core_clk * core , const struct cpg_mssr_info * info ,
2017-06-21 22:24:15 +02:00
struct clk * * clks , void __iomem * base ,
struct raw_notifier_head * notifiers )
2016-05-04 14:32:56 +02:00
{
const struct clk * parent ;
unsigned int mult = 1 ;
unsigned int div = 1 ;
u32 value ;
2018-07-11 13:54:30 +02:00
parent = clks [ core - > parent & 0xffff ] ; /* some types use high bits */
2016-05-04 14:32:56 +02:00
if ( IS_ERR ( parent ) )
return ERR_CAST ( parent ) ;
switch ( core - > type ) {
case CLK_TYPE_GEN3_MAIN :
div = cpg_pll_config - > extal_div ;
break ;
case CLK_TYPE_GEN3_PLL0 :
/*
* PLL0 is a configurable multiplier clock . Register it as a
* fixed factor clock for now as there ' s no generic multiplier
* clock implementation and we currently have no need to change
* the multiplier value .
*/
value = readl ( base + CPG_PLL0CR ) ;
mult = ( ( ( value > > 24 ) & 0x7f ) + 1 ) * 2 ;
2017-03-10 11:46:10 +01:00
if ( cpg_quirks & PLL_ERRATA )
mult * = 2 ;
2016-05-04 14:32:56 +02:00
break ;
case CLK_TYPE_GEN3_PLL1 :
mult = cpg_pll_config - > pll1_mult ;
2017-07-19 16:30:45 +02:00
div = cpg_pll_config - > pll1_div ;
2016-05-04 14:32:56 +02:00
break ;
case CLK_TYPE_GEN3_PLL2 :
/*
* PLL2 is a configurable multiplier clock . Register it as a
* fixed factor clock for now as there ' s no generic multiplier
* clock implementation and we currently have no need to change
* the multiplier value .
*/
value = readl ( base + CPG_PLL2CR ) ;
mult = ( ( ( value > > 24 ) & 0x7f ) + 1 ) * 2 ;
2017-03-10 11:46:10 +01:00
if ( cpg_quirks & PLL_ERRATA )
mult * = 2 ;
2016-05-04 14:32:56 +02:00
break ;
case CLK_TYPE_GEN3_PLL3 :
mult = cpg_pll_config - > pll3_mult ;
2017-07-19 16:30:45 +02:00
div = cpg_pll_config - > pll3_div ;
2016-05-04 14:32:56 +02:00
break ;
case CLK_TYPE_GEN3_PLL4 :
/*
* PLL4 is a configurable multiplier clock . Register it as a
* fixed factor clock for now as there ' s no generic multiplier
* clock implementation and we currently have no need to change
* the multiplier value .
*/
value = readl ( base + CPG_PLL4CR ) ;
mult = ( ( ( value > > 24 ) & 0x7f ) + 1 ) * 2 ;
2017-03-10 11:46:10 +01:00
if ( cpg_quirks & PLL_ERRATA )
mult * = 2 ;
2016-05-04 14:32:56 +02:00
break ;
case CLK_TYPE_GEN3_SD :
2017-06-21 22:51:21 +02:00
return cpg_sd_clk_register ( core , base , __clk_get_name ( parent ) ,
notifiers ) ;
2016-05-04 14:32:56 +02:00
case CLK_TYPE_GEN3_R :
2017-03-10 12:13:37 +01:00
if ( cpg_quirks & RCKCR_CKSEL ) {
2017-06-28 21:15:49 +02:00
struct cpg_simple_notifier * csn ;
csn = kzalloc ( sizeof ( * csn ) , GFP_KERNEL ) ;
if ( ! csn )
return ERR_PTR ( - ENOMEM ) ;
csn - > reg = base + CPG_RCKCR ;
2017-03-10 12:13:37 +01:00
/*
* RINT is default .
* Only if EXTALR is populated , we switch to it .
*/
2017-06-28 21:15:49 +02:00
value = readl ( csn - > reg ) & 0x3f ;
2017-03-10 12:13:37 +01:00
if ( clk_get_rate ( clks [ cpg_clk_extalr ] ) ) {
parent = clks [ cpg_clk_extalr ] ;
2018-07-11 13:54:30 +02:00
value | = CPG_RCKCR_CKSEL ;
2017-03-10 12:13:37 +01:00
}
2017-06-28 21:15:49 +02:00
writel ( value , csn - > reg ) ;
cpg_simple_notifier_register ( notifiers , csn ) ;
2017-03-10 12:13:37 +01:00
break ;
2016-05-04 14:32:56 +02:00
}
2017-03-10 12:13:37 +01:00
/* Select parent clock of RCLK by MD28 */
if ( cpg_mode & BIT ( 28 ) )
parent = clks [ cpg_clk_extalr ] ;
2016-05-04 14:32:56 +02:00
break ;
2018-07-11 14:19:47 +02:00
case CLK_TYPE_GEN3_MDSEL :
2017-07-19 17:39:54 +02:00
/*
2018-07-11 14:19:47 +02:00
* Clock selectable between two parents and two fixed dividers
* using a mode pin
2017-07-19 17:39:54 +02:00
*/
2018-07-11 14:19:47 +02:00
if ( cpg_mode & BIT ( core - > offset ) ) {
2017-07-19 17:39:54 +02:00
div = core - > div & 0xffff ;
} else {
parent = clks [ core - > parent > > 16 ] ;
if ( IS_ERR ( parent ) )
return ERR_CAST ( parent ) ;
div = core - > div > > 16 ;
}
mult = 1 ;
break ;
2018-01-29 19:01:49 +01:00
case CLK_TYPE_GEN3_Z :
return cpg_z_clk_register ( core - > name , __clk_get_name ( parent ) ,
2018-01-29 19:01:50 +01:00
base , CPG_FRQCRC_ZFC_MASK ) ;
case CLK_TYPE_GEN3_Z2 :
return cpg_z_clk_register ( core - > name , __clk_get_name ( parent ) ,
base , CPG_FRQCRC_Z2FC_MASK ) ;
2018-01-29 19:01:49 +01:00
2018-07-11 13:14:44 +02:00
case CLK_TYPE_GEN3_OSC :
/*
* Clock combining OSC EXTAL predivider and a fixed divider
*/
div = cpg_pll_config - > osc_prediv * core - > div ;
break ;
2018-07-11 13:54:30 +02:00
case CLK_TYPE_GEN3_RCKSEL :
/*
* Clock selectable between two parents and two fixed dividers
* using RCKCR . CKSEL
*/
if ( readl ( base + CPG_RCKCR ) & CPG_RCKCR_CKSEL ) {
div = core - > div & 0xffff ;
} else {
parent = clks [ core - > parent > > 16 ] ;
if ( IS_ERR ( parent ) )
return ERR_CAST ( parent ) ;
div = core - > div > > 16 ;
}
break ;
2016-05-04 14:32:56 +02:00
default :
return ERR_PTR ( - EINVAL ) ;
}
return clk_register_fixed_factor ( NULL , core - > name ,
__clk_get_name ( parent ) , 0 , mult , div ) ;
}
int __init rcar_gen3_cpg_init ( const struct rcar_gen3_cpg_pll_config * config ,
2017-03-10 11:36:33 +01:00
unsigned int clk_extalr , u32 mode )
2016-05-04 14:32:56 +02:00
{
2017-03-10 11:46:10 +01:00
const struct soc_device_attribute * attr ;
2016-05-04 14:32:56 +02:00
cpg_pll_config = config ;
cpg_clk_extalr = clk_extalr ;
2017-03-10 11:36:33 +01:00
cpg_mode = mode ;
2017-03-10 11:46:10 +01:00
attr = soc_device_match ( cpg_quirks_match ) ;
if ( attr )
cpg_quirks = ( uintptr_t ) attr - > data ;
pr_debug ( " %s: mode = 0x%x quirks = 0x%x \n " , __func__ , mode , cpg_quirks ) ;
2016-05-04 14:32:56 +02:00
return 0 ;
}