2012-03-16 10:11:20 +04:00
/*
* Copyright ( C ) 2011 Sascha Hauer , Pengutronix < s . hauer @ pengutronix . de >
* Copyright ( C ) 2011 Richard Zhao , Linaro < richard . zhao @ linaro . org >
* Copyright ( C ) 2011 - 2012 Mike Turquette , Linaro Ltd < mturquette @ linaro . org >
*
* 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 .
*
* Adjustable divider clock implementation
*/
# include <linux/clk-provider.h>
# include <linux/module.h>
# include <linux/slab.h>
# include <linux/io.h>
# include <linux/err.h>
# include <linux/string.h>
/*
* DOC : basic adjustable 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 adjustable . clk - > rate = parent - > rate / divisor
* parent - fixed parent . No clk_set_parent support
*/
# define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
# define div_mask(d) ((1 << (d->width)) - 1)
2012-05-17 14:22:13 +04:00
# define is_power_of_two(i) !(i & ~i)
2012-06-29 17:36:32 +04:00
static unsigned int _get_table_maxdiv ( const struct clk_div_table * table )
{
unsigned int maxdiv = 0 ;
const struct clk_div_table * clkt ;
for ( clkt = table ; clkt - > div ; clkt + + )
if ( clkt - > div > maxdiv )
maxdiv = clkt - > div ;
return maxdiv ;
}
2012-05-17 14:22:13 +04:00
static unsigned int _get_maxdiv ( struct clk_divider * divider )
{
if ( divider - > flags & CLK_DIVIDER_ONE_BASED )
return div_mask ( divider ) ;
if ( divider - > flags & CLK_DIVIDER_POWER_OF_TWO )
return 1 < < div_mask ( divider ) ;
2012-06-29 17:36:32 +04:00
if ( divider - > table )
return _get_table_maxdiv ( divider - > table ) ;
2012-05-17 14:22:13 +04:00
return div_mask ( divider ) + 1 ;
}
2012-06-29 17:36:32 +04:00
static unsigned int _get_table_div ( const struct clk_div_table * table ,
unsigned int val )
{
const struct clk_div_table * clkt ;
for ( clkt = table ; clkt - > div ; clkt + + )
if ( clkt - > val = = val )
return clkt - > div ;
return 0 ;
}
2012-05-17 14:22:13 +04:00
static unsigned int _get_div ( struct clk_divider * divider , unsigned int val )
{
if ( divider - > flags & CLK_DIVIDER_ONE_BASED )
return val ;
if ( divider - > flags & CLK_DIVIDER_POWER_OF_TWO )
return 1 < < val ;
2012-06-29 17:36:32 +04:00
if ( divider - > table )
return _get_table_div ( divider - > table , val ) ;
2012-05-17 14:22:13 +04:00
return val + 1 ;
}
2012-06-29 17:36:32 +04:00
static unsigned int _get_table_val ( const struct clk_div_table * table ,
unsigned int div )
{
const struct clk_div_table * clkt ;
for ( clkt = table ; clkt - > div ; clkt + + )
if ( clkt - > div = = div )
return clkt - > val ;
return 0 ;
}
2012-05-17 14:22:13 +04:00
static unsigned int _get_val ( struct clk_divider * divider , u8 div )
{
if ( divider - > flags & CLK_DIVIDER_ONE_BASED )
return div ;
if ( divider - > flags & CLK_DIVIDER_POWER_OF_TWO )
return __ffs ( div ) ;
2012-06-29 17:36:32 +04:00
if ( divider - > table )
return _get_table_val ( divider - > table , div ) ;
2012-05-17 14:22:13 +04:00
return div - 1 ;
}
2012-03-16 10:11:20 +04:00
static unsigned long clk_divider_recalc_rate ( struct clk_hw * hw ,
unsigned long parent_rate )
{
struct clk_divider * divider = to_clk_divider ( hw ) ;
2012-05-17 14:22:13 +04:00
unsigned int div , val ;
2012-03-16 10:11:20 +04:00
2012-05-17 14:22:13 +04:00
val = readl ( divider - > reg ) > > divider - > shift ;
val & = div_mask ( divider ) ;
2012-03-16 10:11:20 +04:00
2012-05-17 14:22:13 +04:00
div = _get_div ( divider , val ) ;
if ( ! div ) {
WARN ( 1 , " %s: Invalid divisor for clock %s \n " , __func__ ,
__clk_get_name ( hw - > clk ) ) ;
return parent_rate ;
}
2012-03-16 10:11:20 +04:00
return parent_rate / div ;
}
/*
* The reverse of DIV_ROUND_UP : The maximum number which
* divided by m is r
*/
# define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1)
2012-06-29 17:36:32 +04:00
static bool _is_valid_table_div ( const struct clk_div_table * table ,
unsigned int div )
{
const struct clk_div_table * clkt ;
for ( clkt = table ; clkt - > div ; clkt + + )
if ( clkt - > div = = div )
return true ;
return false ;
}
static bool _is_valid_div ( struct clk_divider * divider , unsigned int div )
{
if ( divider - > flags & CLK_DIVIDER_POWER_OF_TWO )
return is_power_of_two ( div ) ;
if ( divider - > table )
return _is_valid_table_div ( divider - > table , div ) ;
return true ;
}
2012-03-16 10:11:20 +04:00
static int clk_divider_bestdiv ( struct clk_hw * hw , unsigned long rate ,
unsigned long * best_parent_rate )
{
struct clk_divider * divider = to_clk_divider ( hw ) ;
int i , bestdiv = 0 ;
unsigned long parent_rate , best = 0 , now , maxdiv ;
if ( ! rate )
rate = 1 ;
2012-05-17 14:22:13 +04:00
maxdiv = _get_maxdiv ( divider ) ;
2012-03-16 10:11:20 +04:00
2012-04-12 16:50:17 +04:00
if ( ! ( __clk_get_flags ( hw - > clk ) & CLK_SET_RATE_PARENT ) ) {
parent_rate = * best_parent_rate ;
2012-03-16 10:11:20 +04:00
bestdiv = DIV_ROUND_UP ( parent_rate , rate ) ;
bestdiv = bestdiv = = 0 ? 1 : bestdiv ;
bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv ;
return bestdiv ;
}
/*
* The maximum divider we can use without overflowing
* unsigned long in rate * i below
*/
maxdiv = min ( ULONG_MAX / rate , maxdiv ) ;
for ( i = 1 ; i < = maxdiv ; i + + ) {
2012-06-29 17:36:32 +04:00
if ( ! _is_valid_div ( divider , i ) )
2012-05-17 14:22:13 +04:00
continue ;
2012-03-16 10:11:20 +04:00
parent_rate = __clk_round_rate ( __clk_get_parent ( hw - > clk ) ,
MULT_ROUND_UP ( rate , i ) ) ;
now = parent_rate / i ;
if ( now < = rate & & now > best ) {
bestdiv = i ;
best = now ;
* best_parent_rate = parent_rate ;
}
}
if ( ! bestdiv ) {
2012-05-17 14:22:13 +04:00
bestdiv = _get_maxdiv ( divider ) ;
2012-03-16 10:11:20 +04:00
* best_parent_rate = __clk_round_rate ( __clk_get_parent ( hw - > clk ) , 1 ) ;
}
return bestdiv ;
}
static long clk_divider_round_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long * prate )
{
int div ;
div = clk_divider_bestdiv ( hw , rate , prate ) ;
2012-04-12 16:50:17 +04:00
return * prate / div ;
2012-03-16 10:11:20 +04:00
}
2012-04-12 16:50:18 +04:00
static int clk_divider_set_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long parent_rate )
2012-03-16 10:11:20 +04:00
{
struct clk_divider * divider = to_clk_divider ( hw ) ;
2012-05-17 14:22:13 +04:00
unsigned int div , value ;
2012-03-16 10:11:20 +04:00
unsigned long flags = 0 ;
u32 val ;
2012-04-12 16:50:18 +04:00
div = parent_rate / rate ;
2012-05-17 14:22:13 +04:00
value = _get_val ( divider , div ) ;
2012-03-16 10:11:20 +04:00
2012-05-17 14:22:13 +04:00
if ( value > div_mask ( divider ) )
value = div_mask ( divider ) ;
2012-03-16 10:11:20 +04:00
if ( divider - > lock )
spin_lock_irqsave ( divider - > lock , flags ) ;
val = readl ( divider - > reg ) ;
val & = ~ ( div_mask ( divider ) < < divider - > shift ) ;
2012-05-17 14:22:13 +04:00
val | = value < < divider - > shift ;
2012-03-16 10:11:20 +04:00
writel ( val , divider - > reg ) ;
if ( divider - > lock )
spin_unlock_irqrestore ( divider - > lock , flags ) ;
return 0 ;
}
2012-03-27 11:23:22 +04:00
const struct clk_ops clk_divider_ops = {
2012-03-16 10:11:20 +04:00
. recalc_rate = clk_divider_recalc_rate ,
. round_rate = clk_divider_round_rate ,
. set_rate = clk_divider_set_rate ,
} ;
EXPORT_SYMBOL_GPL ( clk_divider_ops ) ;
2012-06-29 17:36:32 +04:00
static struct clk * _register_divider ( struct device * dev , const char * name ,
2012-03-16 10:11:20 +04:00
const char * parent_name , unsigned long flags ,
void __iomem * reg , u8 shift , u8 width ,
2012-06-29 17:36:32 +04:00
u8 clk_divider_flags , const struct clk_div_table * table ,
spinlock_t * lock )
2012-03-16 10:11:20 +04:00
{
struct clk_divider * div ;
struct clk * clk ;
2012-04-26 09:58:56 +04:00
struct clk_init_data init ;
2012-03-16 10:11:20 +04:00
2012-03-27 04:51:03 +04:00
/* allocate the divider */
2012-03-16 10:11:20 +04:00
div = kzalloc ( sizeof ( struct clk_divider ) , GFP_KERNEL ) ;
if ( ! div ) {
pr_err ( " %s: could not allocate divider clk \n " , __func__ ) ;
2012-03-27 04:51:03 +04:00
return ERR_PTR ( - ENOMEM ) ;
2012-03-16 10:11:20 +04:00
}
2012-04-26 09:58:56 +04:00
init . name = name ;
init . ops = & clk_divider_ops ;
2012-06-01 12:32:47 +04:00
init . flags = flags | CLK_IS_BASIC ;
2012-04-26 09:58:56 +04:00
init . parent_names = ( parent_name ? & parent_name : NULL ) ;
init . num_parents = ( parent_name ? 1 : 0 ) ;
2012-03-16 10:11:20 +04:00
/* struct clk_divider assignments */
div - > reg = reg ;
div - > shift = shift ;
div - > width = width ;
div - > flags = clk_divider_flags ;
div - > lock = lock ;
2012-04-26 09:58:56 +04:00
div - > hw . init = & init ;
2012-06-29 17:36:32 +04:00
div - > table = table ;
2012-03-16 10:11:20 +04:00
2012-03-27 04:51:03 +04:00
/* register the clock */
2012-04-26 09:58:56 +04:00
clk = clk_register ( dev , & div - > hw ) ;
2012-03-16 10:11:20 +04:00
2012-03-27 04:51:03 +04:00
if ( IS_ERR ( clk ) )
kfree ( div ) ;
2012-03-16 10:11:20 +04:00
2012-03-27 04:51:03 +04:00
return clk ;
2012-03-16 10:11:20 +04:00
}
2012-06-29 17:36:32 +04:00
/**
* clk_register_divider - register a divider clock with the clock framework
* @ dev : device registering this clock
* @ name : name of this clock
* @ parent_name : name of clock ' s parent
* @ flags : framework - specific flags
* @ reg : register address to adjust divider
* @ shift : number of bits to shift the bitfield
* @ width : width of the bitfield
* @ clk_divider_flags : divider - specific flags for this clock
* @ lock : shared register lock for this clock
*/
struct clk * clk_register_divider ( struct device * dev , const char * name ,
const char * parent_name , unsigned long flags ,
void __iomem * reg , u8 shift , u8 width ,
u8 clk_divider_flags , spinlock_t * lock )
{
return _register_divider ( dev , name , parent_name , flags , reg , shift ,
width , clk_divider_flags , NULL , lock ) ;
}
/**
* clk_register_divider_table - register a table based divider clock with
* the clock framework
* @ dev : device registering this clock
* @ name : name of this clock
* @ parent_name : name of clock ' s parent
* @ flags : framework - specific flags
* @ reg : register address to adjust divider
* @ shift : number of bits to shift the bitfield
* @ width : width of the bitfield
* @ clk_divider_flags : divider - specific flags for this clock
* @ table : array of divider / value pairs ending with a div set to 0
* @ lock : shared register lock for this clock
*/
struct clk * clk_register_divider_table ( struct device * dev , const char * name ,
const char * parent_name , unsigned long flags ,
void __iomem * reg , u8 shift , u8 width ,
u8 clk_divider_flags , const struct clk_div_table * table ,
spinlock_t * lock )
{
return _register_divider ( dev , name , parent_name , flags , reg , shift ,
width , clk_divider_flags , table , lock ) ;
}