2012-05-03 14:06:14 +04:00
/*
* Copyright ( C ) 2011 Sascha Hauer , Pengutronix < s . hauer @ pengutronix . de >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
* Standard functionality for the common clock API .
*/
# include <linux/module.h>
# include <linux/clk-provider.h>
# include <linux/slab.h>
# include <linux/err.h>
2013-04-12 15:57:44 +04:00
# include <linux/of.h>
2012-05-03 14:06:14 +04:00
/*
* DOC : basic fixed multiplier and divider clock that cannot gate
*
* 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 fixed . clk - > rate = parent - > rate / div * mult
* parent - fixed parent . No clk_set_parent support
*/
# define to_clk_fixed_factor(_hw) container_of(_hw, struct clk_fixed_factor, hw)
static unsigned long clk_factor_recalc_rate ( struct clk_hw * hw ,
unsigned long parent_rate )
{
struct clk_fixed_factor * fix = to_clk_fixed_factor ( hw ) ;
2012-12-03 12:14:37 +04:00
unsigned long long int rate ;
2012-05-03 14:06:14 +04:00
2012-12-03 12:14:37 +04:00
rate = ( unsigned long long int ) parent_rate * fix - > mult ;
do_div ( rate , fix - > div ) ;
return ( unsigned long ) rate ;
2012-05-03 14:06:14 +04:00
}
static long clk_factor_round_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long * prate )
{
struct clk_fixed_factor * fix = to_clk_fixed_factor ( hw ) ;
if ( __clk_get_flags ( hw - > clk ) & CLK_SET_RATE_PARENT ) {
unsigned long best_parent ;
best_parent = ( rate / fix - > mult ) * fix - > div ;
* prate = __clk_round_rate ( __clk_get_parent ( hw - > clk ) ,
best_parent ) ;
}
return ( * prate / fix - > div ) * fix - > mult ;
}
static int clk_factor_set_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long parent_rate )
{
return 0 ;
}
struct clk_ops clk_fixed_factor_ops = {
. round_rate = clk_factor_round_rate ,
. set_rate = clk_factor_set_rate ,
. recalc_rate = clk_factor_recalc_rate ,
} ;
EXPORT_SYMBOL_GPL ( clk_fixed_factor_ops ) ;
struct clk * clk_register_fixed_factor ( struct device * dev , const char * name ,
const char * parent_name , unsigned long flags ,
unsigned int mult , unsigned int div )
{
struct clk_fixed_factor * fix ;
struct clk_init_data init ;
struct clk * clk ;
fix = kmalloc ( sizeof ( * fix ) , GFP_KERNEL ) ;
if ( ! fix ) {
pr_err ( " %s: could not allocate fixed factor clk \n " , __func__ ) ;
return ERR_PTR ( - ENOMEM ) ;
}
/* struct clk_fixed_factor assignments */
fix - > mult = mult ;
fix - > div = div ;
fix - > hw . init = & init ;
init . name = name ;
init . ops = & clk_fixed_factor_ops ;
2012-06-01 12:32:47 +04:00
init . flags = flags | CLK_IS_BASIC ;
2012-05-03 14:06:14 +04:00
init . parent_names = & parent_name ;
init . num_parents = 1 ;
clk = clk_register ( dev , & fix - > hw ) ;
if ( IS_ERR ( clk ) )
kfree ( fix ) ;
return clk ;
}
2013-08-16 06:06:29 +04:00
EXPORT_SYMBOL_GPL ( clk_register_fixed_factor ) ;
2013-04-12 15:57:44 +04:00
# ifdef CONFIG_OF
/**
* of_fixed_factor_clk_setup ( ) - Setup function for simple fixed factor clock
*/
void __init of_fixed_factor_clk_setup ( struct device_node * node )
{
struct clk * clk ;
const char * clk_name = node - > name ;
const char * parent_name ;
u32 div , mult ;
if ( of_property_read_u32 ( node , " clock-div " , & div ) ) {
pr_err ( " %s Fixed factor clock <%s> must have a clock-div property \n " ,
__func__ , node - > name ) ;
return ;
}
if ( of_property_read_u32 ( node , " clock-mult " , & mult ) ) {
2013-09-25 23:08:46 +04:00
pr_err ( " %s Fixed factor clock <%s> must have a clock-mult property \n " ,
2013-04-12 15:57:44 +04:00
__func__ , node - > name ) ;
return ;
}
of_property_read_string ( node , " clock-output-names " , & clk_name ) ;
parent_name = of_clk_get_parent_name ( node , 0 ) ;
clk = clk_register_fixed_factor ( NULL , clk_name , parent_name , 0 ,
mult , div ) ;
if ( ! IS_ERR ( clk ) )
of_clk_add_provider ( node , of_clk_src_simple_get , clk ) ;
}
EXPORT_SYMBOL_GPL ( of_fixed_factor_clk_setup ) ;
CLK_OF_DECLARE ( fixed_factor_clk , " fixed-factor-clock " ,
of_fixed_factor_clk_setup ) ;
# endif