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>
2013-01-15 14:28:05 +04:00
# include <linux/log2.h>
2012-03-16 10:11:20 +04:00
/*
* 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
2014-02-13 14:03:59 +04:00
* rate - rate is adjustable . clk - > rate = DIV_ROUND_UP ( parent - > rate / divisor )
2012-03-16 10:11:20 +04:00
* parent - fixed parent . No clk_set_parent support
*/
# define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
2015-01-20 05:05:29 +03:00
# define div_mask(width) ((1 << (width)) - 1)
2012-05-17 14:22:13 +04:00
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 ;
}
2014-01-29 20:24:07 +04:00
static unsigned int _get_table_mindiv ( const struct clk_div_table * table )
{
unsigned int mindiv = UINT_MAX ;
const struct clk_div_table * clkt ;
for ( clkt = table ; clkt - > div ; clkt + + )
if ( clkt - > div < mindiv )
mindiv = clkt - > div ;
return mindiv ;
}
2015-01-20 05:05:29 +03:00
static unsigned int _get_maxdiv ( const struct clk_div_table * table , u8 width ,
unsigned long flags )
2012-05-17 14:22:13 +04:00
{
2015-01-20 05:05:29 +03:00
if ( flags & CLK_DIVIDER_ONE_BASED )
return div_mask ( width ) ;
if ( flags & CLK_DIVIDER_POWER_OF_TWO )
return 1 < < div_mask ( width ) ;
if ( table )
return _get_table_maxdiv ( table ) ;
return div_mask ( width ) + 1 ;
2012-05-17 14:22:13 +04:00
}
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 ;
}
2015-01-20 05:05:29 +03:00
static unsigned int _get_div ( const struct clk_div_table * table ,
2015-05-15 22:45:47 +03:00
unsigned int val , unsigned long flags , u8 width )
2012-05-17 14:22:13 +04:00
{
2015-01-20 05:05:29 +03:00
if ( flags & CLK_DIVIDER_ONE_BASED )
2012-05-17 14:22:13 +04:00
return val ;
2015-01-20 05:05:29 +03:00
if ( flags & CLK_DIVIDER_POWER_OF_TWO )
2012-05-17 14:22:13 +04:00
return 1 < < val ;
2015-05-15 22:45:47 +03:00
if ( flags & CLK_DIVIDER_MAX_AT_ZERO )
return val ? val : div_mask ( width ) + 1 ;
2015-01-20 05:05:29 +03:00
if ( table )
return _get_table_div ( 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 ;
}
2015-01-20 05:05:29 +03:00
static unsigned int _get_val ( const struct clk_div_table * table ,
2015-05-15 22:45:47 +03:00
unsigned int div , unsigned long flags , u8 width )
2012-05-17 14:22:13 +04:00
{
2015-01-20 05:05:29 +03:00
if ( flags & CLK_DIVIDER_ONE_BASED )
2012-05-17 14:22:13 +04:00
return div ;
2015-01-20 05:05:29 +03:00
if ( flags & CLK_DIVIDER_POWER_OF_TWO )
2012-05-17 14:22:13 +04:00
return __ffs ( div ) ;
2015-05-15 22:45:47 +03:00
if ( flags & CLK_DIVIDER_MAX_AT_ZERO )
return ( div = = div_mask ( width ) + 1 ) ? 0 : div ;
2015-01-20 05:05:29 +03:00
if ( table )
return _get_table_val ( table , div ) ;
2012-05-17 14:22:13 +04:00
return div - 1 ;
}
2012-03-16 10:11:20 +04:00
2015-01-20 05:05:29 +03:00
unsigned long divider_recalc_rate ( struct clk_hw * hw , unsigned long parent_rate ,
unsigned int val ,
const struct clk_div_table * table ,
unsigned long flags )
2012-03-16 10:11:20 +04:00
{
2015-05-15 22:45:47 +03:00
struct clk_divider * divider = to_clk_divider ( hw ) ;
2015-01-20 05:05:29 +03:00
unsigned int div ;
2012-03-16 10:11:20 +04:00
2015-05-15 22:45:47 +03:00
div = _get_div ( table , val , flags , divider - > width ) ;
2012-05-17 14:22:13 +04:00
if ( ! div ) {
2015-01-20 05:05:29 +03:00
WARN ( ! ( flags & CLK_DIVIDER_ALLOW_ZERO ) ,
2013-04-03 02:36:56 +04:00
" %s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set \n " ,
__clk_get_name ( hw - > clk ) ) ;
2012-05-17 14:22:13 +04:00
return parent_rate ;
}
2012-03-16 10:11:20 +04:00
2014-02-13 14:03:59 +04:00
return DIV_ROUND_UP ( parent_rate , div ) ;
2012-03-16 10:11:20 +04:00
}
2015-01-20 05:05:29 +03:00
EXPORT_SYMBOL_GPL ( divider_recalc_rate ) ;
static unsigned long clk_divider_recalc_rate ( struct clk_hw * hw ,
unsigned long parent_rate )
{
struct clk_divider * divider = to_clk_divider ( hw ) ;
unsigned int val ;
val = clk_readl ( divider - > reg ) > > divider - > shift ;
val & = div_mask ( divider - > width ) ;
return divider_recalc_rate ( hw , parent_rate , val , divider - > table ,
divider - > flags ) ;
}
2012-03-16 10:11:20 +04:00
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 ;
}
2015-01-20 05:05:29 +03:00
static bool _is_valid_div ( const struct clk_div_table * table , unsigned int div ,
unsigned long flags )
2012-06-29 17:36:32 +04:00
{
2015-01-20 05:05:29 +03:00
if ( flags & CLK_DIVIDER_POWER_OF_TWO )
2013-01-15 14:28:05 +04:00
return is_power_of_2 ( div ) ;
2015-01-20 05:05:29 +03:00
if ( table )
return _is_valid_table_div ( table , div ) ;
2012-06-29 17:36:32 +04:00
return true ;
}
2014-01-29 20:24:06 +04:00
static int _round_up_table ( const struct clk_div_table * table , int div )
{
const struct clk_div_table * clkt ;
2014-05-07 20:48:52 +04:00
int up = INT_MAX ;
2014-01-29 20:24:06 +04:00
for ( clkt = table ; clkt - > div ; clkt + + ) {
if ( clkt - > div = = div )
return clkt - > div ;
else if ( clkt - > div < div )
continue ;
if ( ( clkt - > div - div ) < ( up - div ) )
up = clkt - > div ;
}
return up ;
}
2014-01-29 20:24:07 +04:00
static int _round_down_table ( const struct clk_div_table * table , int div )
{
const struct clk_div_table * clkt ;
int down = _get_table_mindiv ( table ) ;
for ( clkt = table ; clkt - > div ; clkt + + ) {
if ( clkt - > div = = div )
return clkt - > div ;
else if ( clkt - > div > div )
continue ;
if ( ( div - clkt - > div ) < ( div - down ) )
down = clkt - > div ;
}
return down ;
}
2015-01-20 05:05:29 +03:00
static int _div_round_up ( const struct clk_div_table * table ,
unsigned long parent_rate , unsigned long rate ,
unsigned long flags )
2014-01-29 20:24:06 +04:00
{
int div = DIV_ROUND_UP ( parent_rate , rate ) ;
2015-01-20 05:05:29 +03:00
if ( flags & CLK_DIVIDER_POWER_OF_TWO )
2014-01-29 20:24:06 +04:00
div = __roundup_pow_of_two ( div ) ;
2015-01-20 05:05:29 +03:00
if ( table )
div = _round_up_table ( table , div ) ;
2014-01-29 20:24:06 +04:00
return div ;
}
2015-01-20 05:05:29 +03:00
static int _div_round_closest ( const struct clk_div_table * table ,
unsigned long parent_rate , unsigned long rate ,
unsigned long flags )
2014-01-29 20:24:07 +04:00
{
2015-02-21 13:40:25 +03:00
int up , down ;
2015-02-21 13:40:24 +03:00
unsigned long up_rate , down_rate ;
2014-01-29 20:24:07 +04:00
2015-02-21 13:40:25 +03:00
up = DIV_ROUND_UP ( parent_rate , rate ) ;
down = parent_rate / rate ;
2014-01-29 20:24:07 +04:00
2015-01-20 05:05:29 +03:00
if ( flags & CLK_DIVIDER_POWER_OF_TWO ) {
2015-02-21 13:40:25 +03:00
up = __roundup_pow_of_two ( up ) ;
down = __rounddown_pow_of_two ( down ) ;
2015-01-20 05:05:29 +03:00
} else if ( table ) {
2015-02-21 13:40:25 +03:00
up = _round_up_table ( table , up ) ;
down = _round_down_table ( table , down ) ;
2014-01-29 20:24:07 +04:00
}
2015-02-21 13:40:24 +03:00
up_rate = DIV_ROUND_UP ( parent_rate , up ) ;
down_rate = DIV_ROUND_UP ( parent_rate , down ) ;
return ( rate - up_rate ) < = ( down_rate - rate ) ? up : down ;
2014-01-29 20:24:07 +04:00
}
2015-01-20 05:05:29 +03:00
static int _div_round ( const struct clk_div_table * table ,
unsigned long parent_rate , unsigned long rate ,
unsigned long flags )
2014-01-29 20:24:07 +04:00
{
2015-01-20 05:05:29 +03:00
if ( flags & CLK_DIVIDER_ROUND_CLOSEST )
return _div_round_closest ( table , parent_rate , rate , flags ) ;
2014-01-29 20:24:07 +04:00
2015-01-20 05:05:29 +03:00
return _div_round_up ( table , parent_rate , rate , flags ) ;
2014-01-29 20:24:07 +04:00
}
2015-01-20 05:05:29 +03:00
static bool _is_best_div ( unsigned long rate , unsigned long now ,
unsigned long best , unsigned long flags )
2014-01-29 20:24:07 +04:00
{
2015-01-20 05:05:29 +03:00
if ( flags & CLK_DIVIDER_ROUND_CLOSEST )
2014-01-29 20:24:07 +04:00
return abs ( rate - now ) < abs ( rate - best ) ;
return now < = rate & & now > best ;
}
2015-01-20 05:05:29 +03:00
static int _next_div ( const struct clk_div_table * table , int div ,
unsigned long flags )
2014-01-29 20:24:08 +04:00
{
div + + ;
2015-01-20 05:05:29 +03:00
if ( flags & CLK_DIVIDER_POWER_OF_TWO )
2014-01-29 20:24:08 +04:00
return __roundup_pow_of_two ( div ) ;
2015-01-20 05:05:29 +03:00
if ( table )
return _round_up_table ( table , div ) ;
2014-01-29 20:24:08 +04:00
return div ;
}
2012-03-16 10:11:20 +04:00
static int clk_divider_bestdiv ( struct clk_hw * hw , unsigned long rate ,
2015-01-20 05:05:29 +03:00
unsigned long * best_parent_rate ,
const struct clk_div_table * table , u8 width ,
unsigned long flags )
2012-03-16 10:11:20 +04:00
{
int i , bestdiv = 0 ;
unsigned long parent_rate , best = 0 , now , maxdiv ;
2013-06-02 18:20:55 +04:00
unsigned long parent_rate_saved = * best_parent_rate ;
2012-03-16 10:11:20 +04:00
if ( ! rate )
rate = 1 ;
2015-01-20 05:05:29 +03:00
maxdiv = _get_maxdiv ( table , width , flags ) ;
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 ;
2015-01-20 05:05:29 +03:00
bestdiv = _div_round ( table , parent_rate , rate , flags ) ;
2012-03-16 10:11:20 +04:00
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 ) ;
2015-01-20 05:05:29 +03:00
for ( i = 1 ; i < = maxdiv ; i = _next_div ( table , i , flags ) ) {
if ( ! _is_valid_div ( table , i , flags ) )
2012-05-17 14:22:13 +04:00
continue ;
2013-06-02 18:20:55 +04:00
if ( rate * i = = parent_rate_saved ) {
/*
* It ' s the most ideal case if the requested rate can be
* divided from parent clock without needing to change
* parent rate , so return the divider immediately .
*/
* best_parent_rate = parent_rate_saved ;
return i ;
}
2012-03-16 10:11:20 +04:00
parent_rate = __clk_round_rate ( __clk_get_parent ( hw - > clk ) ,
2015-02-21 13:40:23 +03:00
rate * i ) ;
2014-02-13 14:03:59 +04:00
now = DIV_ROUND_UP ( parent_rate , i ) ;
2015-01-20 05:05:29 +03:00
if ( _is_best_div ( rate , now , best , flags ) ) {
2012-03-16 10:11:20 +04:00
bestdiv = i ;
best = now ;
* best_parent_rate = parent_rate ;
}
}
if ( ! bestdiv ) {
2015-01-20 05:05:29 +03:00
bestdiv = _get_maxdiv ( table , width , flags ) ;
2012-03-16 10:11:20 +04:00
* best_parent_rate = __clk_round_rate ( __clk_get_parent ( hw - > clk ) , 1 ) ;
}
return bestdiv ;
}
2015-01-20 05:05:29 +03:00
long divider_round_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long * prate , const struct clk_div_table * table ,
u8 width , unsigned long flags )
2012-03-16 10:11:20 +04:00
{
int div ;
2015-01-20 05:05:29 +03:00
div = clk_divider_bestdiv ( hw , rate , prate , table , width , flags ) ;
2012-03-16 10:11:20 +04:00
2014-02-13 14:03:59 +04:00
return DIV_ROUND_UP ( * prate , div ) ;
2012-03-16 10:11:20 +04:00
}
2015-01-20 05:05:29 +03:00
EXPORT_SYMBOL_GPL ( divider_round_rate ) ;
2012-03-16 10:11:20 +04:00
2015-01-20 05:05:29 +03:00
static long clk_divider_round_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long * prate )
2012-03-16 10:11:20 +04:00
{
struct clk_divider * divider = to_clk_divider ( hw ) ;
2015-01-20 05:05:29 +03:00
int bestdiv ;
/* if read only, just return current value */
if ( divider - > flags & CLK_DIVIDER_READ_ONLY ) {
bestdiv = readl ( divider - > reg ) > > divider - > shift ;
bestdiv & = div_mask ( divider - > width ) ;
2015-05-15 22:45:47 +03:00
bestdiv = _get_div ( divider - > table , bestdiv , divider - > flags ,
divider - > width ) ;
2015-02-24 13:39:25 +03:00
return DIV_ROUND_UP ( * prate , bestdiv ) ;
2015-01-20 05:05:29 +03:00
}
return divider_round_rate ( hw , rate , prate , divider - > table ,
divider - > width , divider - > flags ) ;
}
int divider_get_val ( unsigned long rate , unsigned long parent_rate ,
const struct clk_div_table * table , u8 width ,
unsigned long flags )
{
2012-05-17 14:22:13 +04:00
unsigned int div , value ;
2012-03-16 10:11:20 +04:00
2014-02-13 14:03:59 +04:00
div = DIV_ROUND_UP ( parent_rate , rate ) ;
2014-01-29 20:24:06 +04:00
2015-01-20 05:05:29 +03:00
if ( ! _is_valid_div ( table , div , flags ) )
2014-01-29 20:24:06 +04:00
return - EINVAL ;
2015-05-15 22:45:47 +03:00
value = _get_val ( table , div , flags , width ) ;
2015-01-20 05:05:29 +03:00
return min_t ( unsigned int , value , div_mask ( width ) ) ;
}
EXPORT_SYMBOL_GPL ( divider_get_val ) ;
static int clk_divider_set_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long parent_rate )
{
struct clk_divider * divider = to_clk_divider ( hw ) ;
unsigned int value ;
unsigned long flags = 0 ;
u32 val ;
2012-03-16 10:11:20 +04:00
2015-01-20 05:05:29 +03:00
value = divider_get_val ( rate , parent_rate , divider - > table ,
divider - > width , divider - > flags ) ;
2012-03-16 10:11:20 +04:00
if ( divider - > lock )
spin_lock_irqsave ( divider - > lock , flags ) ;
2013-06-08 18:47:18 +04:00
if ( divider - > flags & CLK_DIVIDER_HIWORD_MASK ) {
2015-01-20 05:05:29 +03:00
val = div_mask ( divider - > width ) < < ( divider - > shift + 16 ) ;
2013-06-08 18:47:18 +04:00
} else {
2013-07-22 16:14:40 +04:00
val = clk_readl ( divider - > reg ) ;
2015-01-20 05:05:29 +03:00
val & = ~ ( div_mask ( divider - > width ) < < divider - > shift ) ;
2013-06-08 18:47:18 +04:00
}
2012-05-17 14:22:13 +04:00
val | = value < < divider - > shift ;
2013-07-22 16:14:40 +04:00
clk_writel ( val , divider - > reg ) ;
2012-03-16 10:11:20 +04:00
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
2013-06-08 18:47:18 +04:00
if ( clk_divider_flags & CLK_DIVIDER_HIWORD_MASK ) {
if ( width + shift > 16 ) {
pr_warn ( " divider value exceeds LOWORD field \n " ) ;
return ERR_PTR ( - EINVAL ) ;
}
}
2012-03-27 04:51:03 +04:00
/* allocate the divider */
2015-05-15 02:47:10 +03:00
div = kzalloc ( sizeof ( * div ) , GFP_KERNEL ) ;
if ( ! div )
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 ;
2014-11-14 18:32:09 +03:00
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 ) ;
}
2013-08-02 20:14:07 +04:00
EXPORT_SYMBOL_GPL ( clk_register_divider ) ;
2012-06-29 17:36:32 +04:00
/**
* 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 ) ;
}
2013-08-02 20:14:07 +04:00
EXPORT_SYMBOL_GPL ( clk_register_divider_table ) ;
2015-01-05 12:52:40 +03:00
void clk_unregister_divider ( struct clk * clk )
{
struct clk_divider * div ;
struct clk_hw * hw ;
hw = __clk_get_hw ( clk ) ;
if ( ! hw )
return ;
div = to_clk_divider ( hw ) ;
clk_unregister ( clk ) ;
kfree ( div ) ;
}
EXPORT_SYMBOL_GPL ( clk_unregister_divider ) ;