2018-08-22 00:02:14 +02:00
// SPDX-License-Identifier: GPL-2.0
2013-10-17 23:54:07 +02:00
/*
* r8a7790 Common Clock Framework support
*
* Copyright ( C ) 2013 Renesas Solutions Corp .
*
* Contact : Laurent Pinchart < laurent . pinchart @ ideasonboard . com >
*/
# include <linux/clk-provider.h>
# include <linux/init.h>
# include <linux/io.h>
# include <linux/kernel.h>
2017-06-21 22:34:33 +02:00
# include <linux/notifier.h>
2013-10-17 23:54:07 +02:00
# include <linux/of.h>
# include <linux/of_address.h>
2017-06-21 22:34:33 +02:00
# include <linux/pm.h>
2015-06-23 15:09:27 +02:00
# include <linux/slab.h>
2013-10-17 23:54:07 +02:00
2015-10-16 11:41:19 +02:00
# include "clk-div6.h"
2013-10-17 23:54:07 +02:00
# define CPG_DIV6_CKSTP BIT(8)
# define CPG_DIV6_DIV(d) ((d) & 0x3f)
# define CPG_DIV6_DIV_MASK 0x3f
/**
2014-02-24 20:57:11 +01:00
* struct div6_clock - CPG 6 bit divider clock
2013-10-17 23:54:07 +02:00
* @ hw : handle between common and hardware - specific interfaces
* @ reg : IO - remapped register
* @ div : divisor value ( 1 - 64 )
2017-06-21 22:02:33 +02:00
* @ src_shift : Shift to access the register bits to select the parent clock
* @ src_width : Number of register bits to select the parent clock ( may be 0 )
2017-06-21 22:34:33 +02:00
* @ nb : Notifier block to save / restore clock state for system resume
2019-06-12 17:22:18 +02:00
* @ parents : Array to map from valid parent clocks indices to hardware indices
2013-10-17 23:54:07 +02:00
*/
struct div6_clock {
struct clk_hw hw ;
void __iomem * reg ;
unsigned int div ;
2014-11-07 16:51:07 +01:00
u32 src_shift ;
u32 src_width ;
2017-06-21 22:34:33 +02:00
struct notifier_block nb ;
2019-06-12 17:22:18 +02:00
u8 parents [ ] ;
2013-10-17 23:54:07 +02:00
} ;
# define to_div6_clock(_hw) container_of(_hw, struct div6_clock, hw)
static int cpg_div6_clock_enable ( struct clk_hw * hw )
{
struct div6_clock * clock = to_div6_clock ( hw ) ;
2014-11-07 16:51:07 +01:00
u32 val ;
2013-10-17 23:54:07 +02:00
2018-03-15 10:43:12 +01:00
val = ( readl ( clock - > reg ) & ~ ( CPG_DIV6_DIV_MASK | CPG_DIV6_CKSTP ) )
2014-11-07 16:51:07 +01:00
| CPG_DIV6_DIV ( clock - > div - 1 ) ;
2018-03-15 10:43:12 +01:00
writel ( val , clock - > reg ) ;
2013-10-17 23:54:07 +02:00
return 0 ;
}
static void cpg_div6_clock_disable ( struct clk_hw * hw )
{
struct div6_clock * clock = to_div6_clock ( hw ) ;
2014-11-24 15:57:59 +01:00
u32 val ;
2013-10-17 23:54:07 +02:00
2018-03-15 10:43:12 +01:00
val = readl ( clock - > reg ) ;
2014-11-24 15:57:59 +01:00
val | = CPG_DIV6_CKSTP ;
/*
* DIV6 clocks require the divisor field to be non - zero when stopping
* the clock . However , some clocks ( e . g . ZB on sh73a0 ) fail to be
* re - enabled later if the divisor field is changed when stopping the
* clock
2013-10-17 23:54:07 +02:00
*/
2014-11-24 15:57:59 +01:00
if ( ! ( val & CPG_DIV6_DIV_MASK ) )
val | = CPG_DIV6_DIV_MASK ;
2018-03-15 10:43:12 +01:00
writel ( val , clock - > reg ) ;
2013-10-17 23:54:07 +02:00
}
static int cpg_div6_clock_is_enabled ( struct clk_hw * hw )
{
struct div6_clock * clock = to_div6_clock ( hw ) ;
2018-03-15 10:43:12 +01:00
return ! ( readl ( clock - > reg ) & CPG_DIV6_CKSTP ) ;
2013-10-17 23:54:07 +02:00
}
static unsigned long cpg_div6_clock_recalc_rate ( struct clk_hw * hw ,
unsigned long parent_rate )
{
struct div6_clock * clock = to_div6_clock ( hw ) ;
2016-02-18 15:16:02 +01:00
return parent_rate / clock - > div ;
2013-10-17 23:54:07 +02:00
}
static unsigned int cpg_div6_clock_calc_div ( unsigned long rate ,
unsigned long parent_rate )
{
unsigned int div ;
2015-02-04 13:27:21 +01:00
if ( ! rate )
rate = 1 ;
2013-10-17 23:54:07 +02:00
div = DIV_ROUND_CLOSEST ( parent_rate , rate ) ;
return clamp_t ( unsigned int , div , 1 , 64 ) ;
}
static long cpg_div6_clock_round_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long * parent_rate )
{
unsigned int div = cpg_div6_clock_calc_div ( rate , * parent_rate ) ;
return * parent_rate / div ;
}
static int cpg_div6_clock_set_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long parent_rate )
{
struct div6_clock * clock = to_div6_clock ( hw ) ;
unsigned int div = cpg_div6_clock_calc_div ( rate , parent_rate ) ;
2014-11-07 16:51:07 +01:00
u32 val ;
2013-10-17 23:54:07 +02:00
clock - > div = div ;
2018-03-15 10:43:12 +01:00
val = readl ( clock - > reg ) & ~ CPG_DIV6_DIV_MASK ;
2013-10-17 23:54:07 +02:00
/* Only program the new divisor if the clock isn't stopped. */
2014-11-07 16:51:07 +01:00
if ( ! ( val & CPG_DIV6_CKSTP ) )
2018-03-15 10:43:12 +01:00
writel ( val | CPG_DIV6_DIV ( clock - > div - 1 ) , clock - > reg ) ;
2014-11-07 16:51:07 +01:00
return 0 ;
}
static u8 cpg_div6_clock_get_parent ( struct clk_hw * hw )
{
struct div6_clock * clock = to_div6_clock ( hw ) ;
unsigned int i ;
u8 hw_index ;
if ( clock - > src_width = = 0 )
return 0 ;
2018-03-15 10:43:12 +01:00
hw_index = ( readl ( clock - > reg ) > > clock - > src_shift ) &
2014-11-07 16:51:07 +01:00
( BIT ( clock - > src_width ) - 1 ) ;
2015-06-25 16:53:23 -07:00
for ( i = 0 ; i < clk_hw_get_num_parents ( hw ) ; i + + ) {
2014-11-07 16:51:07 +01:00
if ( clock - > parents [ i ] = = hw_index )
return i ;
}
pr_err ( " %s: %s DIV6 clock set to invalid parent %u \n " ,
2015-08-12 11:42:23 -07:00
__func__ , clk_hw_get_name ( hw ) , hw_index ) ;
2014-11-07 16:51:07 +01:00
return 0 ;
}
static int cpg_div6_clock_set_parent ( struct clk_hw * hw , u8 index )
{
struct div6_clock * clock = to_div6_clock ( hw ) ;
u8 hw_index ;
u32 mask ;
2015-06-25 16:53:23 -07:00
if ( index > = clk_hw_get_num_parents ( hw ) )
2014-11-07 16:51:07 +01:00
return - EINVAL ;
mask = ~ ( ( BIT ( clock - > src_width ) - 1 ) < < clock - > src_shift ) ;
hw_index = clock - > parents [ index ] ;
2018-03-15 10:43:12 +01:00
writel ( ( readl ( clock - > reg ) & mask ) | ( hw_index < < clock - > src_shift ) ,
clock - > reg ) ;
2013-10-17 23:54:07 +02:00
return 0 ;
}
static const struct clk_ops cpg_div6_clock_ops = {
. enable = cpg_div6_clock_enable ,
. disable = cpg_div6_clock_disable ,
. is_enabled = cpg_div6_clock_is_enabled ,
2014-11-07 16:51:07 +01:00
. get_parent = cpg_div6_clock_get_parent ,
. set_parent = cpg_div6_clock_set_parent ,
2013-10-17 23:54:07 +02:00
. recalc_rate = cpg_div6_clock_recalc_rate ,
. round_rate = cpg_div6_clock_round_rate ,
. set_rate = cpg_div6_clock_set_rate ,
} ;
2017-06-21 22:34:33 +02:00
static int cpg_div6_clock_notifier_call ( struct notifier_block * nb ,
unsigned long action , void * data )
{
struct div6_clock * clock = container_of ( nb , struct div6_clock , nb ) ;
switch ( action ) {
case PM_EVENT_RESUME :
/*
* TODO : This does not yet support DIV6 clocks with multiple
* parents , as the parent selection bits are not restored .
* Fortunately so far such DIV6 clocks are found only on
* R / SH - Mobile SoCs , while the resume functionality is only
* needed on R - Car Gen3 .
*/
if ( __clk_get_enable_count ( clock - > hw . clk ) )
cpg_div6_clock_enable ( & clock - > hw ) ;
else
cpg_div6_clock_disable ( & clock - > hw ) ;
return NOTIFY_OK ;
}
return NOTIFY_DONE ;
}
2015-10-16 11:41:19 +02:00
/**
* cpg_div6_register - Register a DIV6 clock
* @ name : Name of the DIV6 clock
* @ num_parents : Number of parent clocks of the DIV6 clock ( 1 , 4 , or 8 )
* @ parent_names : Array containing the names of the parent clocks
* @ reg : Mapped register used to control the DIV6 clock
2017-06-21 22:34:33 +02:00
* @ notifiers : Optional notifier chain to save / restore state for system resume
2015-10-16 11:41:19 +02:00
*/
struct clk * __init cpg_div6_register ( const char * name ,
unsigned int num_parents ,
const char * * parent_names ,
2017-06-21 22:34:33 +02:00
void __iomem * reg ,
struct raw_notifier_head * notifiers )
2013-10-17 23:54:07 +02:00
{
2015-10-16 11:41:19 +02:00
unsigned int valid_parents ;
2013-10-17 23:54:07 +02:00
struct clk_init_data init ;
struct div6_clock * clock ;
struct clk * clk ;
2014-11-07 16:51:07 +01:00
unsigned int i ;
2013-10-17 23:54:07 +02:00
2019-06-12 17:22:18 +02:00
clock = kzalloc ( struct_size ( clock , parents , num_parents ) , GFP_KERNEL ) ;
2014-11-07 16:51:07 +01:00
if ( ! clock )
2015-10-16 11:41:19 +02:00
return ERR_PTR ( - ENOMEM ) ;
2014-11-07 16:51:07 +01:00
2015-10-16 11:41:19 +02:00
clock - > reg = reg ;
2014-11-07 16:51:07 +01:00
2015-10-16 11:41:19 +02:00
/*
* Read the divisor . Disabling the clock overwrites the divisor , so we
* need to cache its value for the enable operation .
2013-10-17 23:54:07 +02:00
*/
2018-03-15 10:43:12 +01:00
clock - > div = ( readl ( clock - > reg ) & CPG_DIV6_DIV_MASK ) + 1 ;
2013-10-17 23:54:07 +02:00
2014-11-07 16:51:07 +01:00
switch ( num_parents ) {
case 1 :
/* fixed parent clock */
clock - > src_shift = clock - > src_width = 0 ;
break ;
case 4 :
/* clock with EXSRC bits 6-7 */
clock - > src_shift = 6 ;
clock - > src_width = 2 ;
break ;
case 8 :
/* VCLK with EXSRC bits 12-14 */
clock - > src_shift = 12 ;
clock - > src_width = 3 ;
break ;
default :
pr_err ( " %s: invalid number of parents for DIV6 clock %s \n " ,
2015-10-16 11:41:19 +02:00
__func__ , name ) ;
clk = ERR_PTR ( - EINVAL ) ;
2019-06-12 17:22:18 +02:00
goto free_clock ;
2015-10-16 11:41:19 +02:00
}
/* Filter out invalid parents */
for ( i = 0 , valid_parents = 0 ; i < num_parents ; i + + ) {
if ( parent_names [ i ] ) {
parent_names [ valid_parents ] = parent_names [ i ] ;
clock - > parents [ valid_parents ] = i ;
valid_parents + + ;
}
2013-10-17 23:54:07 +02:00
}
/* Register the clock. */
2015-10-16 11:41:19 +02:00
init . name = name ;
2013-10-17 23:54:07 +02:00
init . ops = & cpg_div6_clock_ops ;
2018-11-30 11:05:35 -08:00
init . flags = 0 ;
2014-11-07 16:51:07 +01:00
init . parent_names = parent_names ;
init . num_parents = valid_parents ;
2013-10-17 23:54:07 +02:00
clock - > hw . init = & init ;
clk = clk_register ( NULL , & clock - > hw ) ;
2015-10-16 11:41:19 +02:00
if ( IS_ERR ( clk ) )
2019-06-12 17:22:18 +02:00
goto free_clock ;
2015-10-16 11:41:19 +02:00
2017-06-21 22:34:33 +02:00
if ( notifiers ) {
clock - > nb . notifier_call = cpg_div6_clock_notifier_call ;
raw_notifier_chain_register ( notifiers , & clock - > nb ) ;
}
2015-10-16 11:41:19 +02:00
return clk ;
free_clock :
kfree ( clock ) ;
return clk ;
}
static void __init cpg_div6_clock_init ( struct device_node * np )
{
unsigned int num_parents ;
const char * * parent_names ;
const char * clk_name = np - > name ;
void __iomem * reg ;
struct clk * clk ;
unsigned int i ;
num_parents = of_clk_get_parent_count ( np ) ;
if ( num_parents < 1 ) {
2018-08-28 10:44:29 -05:00
pr_err ( " %s: no parent found for %pOFn DIV6 clock \n " ,
__func__ , np ) ;
2015-10-16 11:41:19 +02:00
return ;
}
parent_names = kmalloc_array ( num_parents , sizeof ( * parent_names ) ,
GFP_KERNEL ) ;
if ( ! parent_names )
return ;
reg = of_iomap ( np , 0 ) ;
if ( reg = = NULL ) {
2018-08-28 10:44:29 -05:00
pr_err ( " %s: failed to map %pOFn DIV6 clock register \n " ,
__func__ , np ) ;
2015-10-16 11:41:19 +02:00
goto error ;
}
/* Parse the DT properties. */
of_property_read_string ( np , " clock-output-names " , & clk_name ) ;
for ( i = 0 ; i < num_parents ; i + + )
parent_names [ i ] = of_clk_get_parent_name ( np , i ) ;
2017-06-21 22:34:33 +02:00
clk = cpg_div6_register ( clk_name , num_parents , parent_names , reg , NULL ) ;
2013-10-17 23:54:07 +02:00
if ( IS_ERR ( clk ) ) {
2018-08-28 10:44:29 -05:00
pr_err ( " %s: failed to register %pOFn DIV6 clock (%ld) \n " ,
__func__ , np , PTR_ERR ( clk ) ) ;
2013-10-17 23:54:07 +02:00
goto error ;
}
of_clk_add_provider ( np , of_clk_src_simple_get , clk ) ;
2014-11-07 16:51:07 +01:00
kfree ( parent_names ) ;
2013-10-17 23:54:07 +02:00
return ;
error :
2015-10-16 11:41:19 +02:00
if ( reg )
iounmap ( reg ) ;
2014-11-07 16:51:07 +01:00
kfree ( parent_names ) ;
2013-10-17 23:54:07 +02:00
}
CLK_OF_DECLARE ( cpg_div6_clk , " renesas,cpg-div6-clock " , cpg_div6_clock_init ) ;