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>
/*
* 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 ;
}