2013-10-18 01:54:07 +04:00
/*
* r8a7790 Common Clock Framework support
*
* Copyright ( C ) 2013 Renesas Solutions Corp .
*
* Contact : Laurent Pinchart < laurent . pinchart @ ideasonboard . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; version 2 of the License .
*/
# include <linux/clk-provider.h>
# include <linux/init.h>
# include <linux/io.h>
# include <linux/kernel.h>
# include <linux/of.h>
# include <linux/of_address.h>
2015-06-23 16:09:27 +03:00
# include <linux/slab.h>
2013-10-18 01:54:07 +04:00
2015-10-16 12:41:19 +03:00
# include "clk-div6.h"
2013-10-18 01:54:07 +04:00
# define CPG_DIV6_CKSTP BIT(8)
# define CPG_DIV6_DIV(d) ((d) & 0x3f)
# define CPG_DIV6_DIV_MASK 0x3f
/**
2014-02-24 23:57:11 +04:00
* struct div6_clock - CPG 6 bit divider clock
2013-10-18 01:54:07 +04:00
* @ hw : handle between common and hardware - specific interfaces
* @ reg : IO - remapped register
* @ div : divisor value ( 1 - 64 )
*/
struct div6_clock {
struct clk_hw hw ;
void __iomem * reg ;
unsigned int div ;
2014-11-07 18:51:07 +03:00
u32 src_shift ;
u32 src_width ;
u8 * parents ;
2013-10-18 01:54:07 +04: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 18:51:07 +03:00
u32 val ;
2013-10-18 01:54:07 +04:00
2014-11-07 18:51:07 +03:00
val = ( clk_readl ( clock - > reg ) & ~ ( CPG_DIV6_DIV_MASK | CPG_DIV6_CKSTP ) )
| CPG_DIV6_DIV ( clock - > div - 1 ) ;
clk_writel ( val , clock - > reg ) ;
2013-10-18 01:54:07 +04:00
return 0 ;
}
static void cpg_div6_clock_disable ( struct clk_hw * hw )
{
struct div6_clock * clock = to_div6_clock ( hw ) ;
2014-11-24 17:57:59 +03:00
u32 val ;
2013-10-18 01:54:07 +04:00
2014-11-24 17:57:59 +03:00
val = clk_readl ( clock - > reg ) ;
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-18 01:54:07 +04:00
*/
2014-11-24 17:57:59 +03:00
if ( ! ( val & CPG_DIV6_DIV_MASK ) )
val | = CPG_DIV6_DIV_MASK ;
clk_writel ( val , clock - > reg ) ;
2013-10-18 01:54:07 +04:00
}
static int cpg_div6_clock_is_enabled ( struct clk_hw * hw )
{
struct div6_clock * clock = to_div6_clock ( hw ) ;
return ! ( clk_readl ( clock - > reg ) & CPG_DIV6_CKSTP ) ;
}
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 17:16:02 +03:00
return parent_rate / clock - > div ;
2013-10-18 01:54:07 +04:00
}
static unsigned int cpg_div6_clock_calc_div ( unsigned long rate ,
unsigned long parent_rate )
{
unsigned int div ;
2015-02-04 15:27:21 +03:00
if ( ! rate )
rate = 1 ;
2013-10-18 01:54:07 +04: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 18:51:07 +03:00
u32 val ;
2013-10-18 01:54:07 +04:00
clock - > div = div ;
2014-11-07 18:51:07 +03:00
val = clk_readl ( clock - > reg ) & ~ CPG_DIV6_DIV_MASK ;
2013-10-18 01:54:07 +04:00
/* Only program the new divisor if the clock isn't stopped. */
2014-11-07 18:51:07 +03:00
if ( ! ( val & CPG_DIV6_CKSTP ) )
clk_writel ( val | CPG_DIV6_DIV ( clock - > div - 1 ) , clock - > reg ) ;
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 ;
hw_index = ( clk_readl ( clock - > reg ) > > clock - > src_shift ) &
( BIT ( clock - > src_width ) - 1 ) ;
2015-06-26 02:53:23 +03:00
for ( i = 0 ; i < clk_hw_get_num_parents ( hw ) ; i + + ) {
2014-11-07 18:51:07 +03:00
if ( clock - > parents [ i ] = = hw_index )
return i ;
}
pr_err ( " %s: %s DIV6 clock set to invalid parent %u \n " ,
2015-08-12 21:42:23 +03:00
__func__ , clk_hw_get_name ( hw ) , hw_index ) ;
2014-11-07 18:51:07 +03: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-26 02:53:23 +03:00
if ( index > = clk_hw_get_num_parents ( hw ) )
2014-11-07 18:51:07 +03:00
return - EINVAL ;
mask = ~ ( ( BIT ( clock - > src_width ) - 1 ) < < clock - > src_shift ) ;
hw_index = clock - > parents [ index ] ;
clk_writel ( ( clk_readl ( clock - > reg ) & mask ) |
( hw_index < < clock - > src_shift ) , clock - > reg ) ;
2013-10-18 01:54:07 +04: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 18:51:07 +03:00
. get_parent = cpg_div6_clock_get_parent ,
. set_parent = cpg_div6_clock_set_parent ,
2013-10-18 01:54:07 +04:00
. recalc_rate = cpg_div6_clock_recalc_rate ,
. round_rate = cpg_div6_clock_round_rate ,
. set_rate = cpg_div6_clock_set_rate ,
} ;
2015-10-16 12:41:19 +03: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
*/
struct clk * __init cpg_div6_register ( const char * name ,
unsigned int num_parents ,
const char * * parent_names ,
void __iomem * reg )
2013-10-18 01:54:07 +04:00
{
2015-10-16 12:41:19 +03:00
unsigned int valid_parents ;
2013-10-18 01:54:07 +04:00
struct clk_init_data init ;
struct div6_clock * clock ;
struct clk * clk ;
2014-11-07 18:51:07 +03:00
unsigned int i ;
2013-10-18 01:54:07 +04:00
clock = kzalloc ( sizeof ( * clock ) , GFP_KERNEL ) ;
2014-11-07 18:51:07 +03:00
if ( ! clock )
2015-10-16 12:41:19 +03:00
return ERR_PTR ( - ENOMEM ) ;
2014-11-07 18:51:07 +03:00
2015-10-16 12:41:19 +03:00
clock - > parents = kmalloc_array ( num_parents , sizeof ( * clock - > parents ) ,
GFP_KERNEL ) ;
if ( ! clock - > parents ) {
clk = ERR_PTR ( - ENOMEM ) ;
goto free_clock ;
2013-10-18 01:54:07 +04:00
}
2015-10-16 12:41:19 +03:00
clock - > reg = reg ;
2014-11-07 18:51:07 +03:00
2015-10-16 12:41:19 +03:00
/*
* Read the divisor . Disabling the clock overwrites the divisor , so we
* need to cache its value for the enable operation .
2013-10-18 01:54:07 +04:00
*/
clock - > div = ( clk_readl ( clock - > reg ) & CPG_DIV6_DIV_MASK ) + 1 ;
2014-11-07 18:51:07 +03: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 12:41:19 +03:00
__func__ , name ) ;
clk = ERR_PTR ( - EINVAL ) ;
goto free_parents ;
}
/* 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-18 01:54:07 +04:00
}
/* Register the clock. */
2015-10-16 12:41:19 +03:00
init . name = name ;
2013-10-18 01:54:07 +04:00
init . ops = & cpg_div6_clock_ops ;
init . flags = CLK_IS_BASIC ;
2014-11-07 18:51:07 +03:00
init . parent_names = parent_names ;
init . num_parents = valid_parents ;
2013-10-18 01:54:07 +04:00
clock - > hw . init = & init ;
clk = clk_register ( NULL , & clock - > hw ) ;
2015-10-16 12:41:19 +03:00
if ( IS_ERR ( clk ) )
goto free_parents ;
return clk ;
free_parents :
kfree ( clock - > parents ) ;
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 ) {
pr_err ( " %s: no parent found for %s DIV6 clock \n " ,
__func__ , np - > name ) ;
return ;
}
parent_names = kmalloc_array ( num_parents , sizeof ( * parent_names ) ,
GFP_KERNEL ) ;
if ( ! parent_names )
return ;
reg = of_iomap ( np , 0 ) ;
if ( reg = = NULL ) {
pr_err ( " %s: failed to map %s DIV6 clock register \n " ,
__func__ , np - > name ) ;
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 ) ;
clk = cpg_div6_register ( clk_name , num_parents , parent_names , reg ) ;
2013-10-18 01:54:07 +04:00
if ( IS_ERR ( clk ) ) {
pr_err ( " %s: failed to register %s DIV6 clock (%ld) \n " ,
__func__ , np - > name , PTR_ERR ( clk ) ) ;
goto error ;
}
of_clk_add_provider ( np , of_clk_src_simple_get , clk ) ;
2014-11-07 18:51:07 +03:00
kfree ( parent_names ) ;
2013-10-18 01:54:07 +04:00
return ;
error :
2015-10-16 12:41:19 +03:00
if ( reg )
iounmap ( reg ) ;
2014-11-07 18:51:07 +03:00
kfree ( parent_names ) ;
2013-10-18 01:54:07 +04:00
}
CLK_OF_DECLARE ( cpg_div6_clk , " renesas,cpg-div6-clock " , cpg_div6_clock_init ) ;