2010-04-01 12:30:46 +01:00
/*
* arch / arm / plat - spear / clock . c
*
* Clock framework for SPEAr platform
*
* Copyright ( C ) 2009 ST Microelectronics
* Viresh Kumar < viresh . kumar @ st . com >
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed " as is " without any
* warranty of any kind , whether express or implied .
*/
# include <linux/bug.h>
2011-02-16 07:40:39 +01:00
# include <linux/clk.h>
2011-02-16 07:40:40 +01:00
# include <linux/debugfs.h>
2010-04-01 12:30:46 +01:00
# include <linux/err.h>
# include <linux/io.h>
# include <linux/list.h>
# include <linux/module.h>
# include <linux/spinlock.h>
# include <plat/clock.h>
static DEFINE_SPINLOCK ( clocks_lock ) ;
static LIST_HEAD ( root_clks ) ;
2011-02-16 07:40:40 +01:00
# ifdef CONFIG_DEBUG_FS
static LIST_HEAD ( clocks ) ;
# endif
2010-04-01 12:30:46 +01:00
2011-02-16 07:40:39 +01:00
static void propagate_rate ( struct clk * , int on_init ) ;
2011-02-16 07:40:40 +01:00
# ifdef CONFIG_DEBUG_FS
static int clk_debugfs_reparent ( struct clk * ) ;
# endif
2010-04-01 12:30:46 +01:00
static int generic_clk_enable ( struct clk * clk )
{
unsigned int val ;
if ( ! clk - > en_reg )
return - EFAULT ;
val = readl ( clk - > en_reg ) ;
if ( unlikely ( clk - > flags & RESET_TO_ENABLE ) )
val & = ~ ( 1 < < clk - > en_reg_bit ) ;
else
val | = 1 < < clk - > en_reg_bit ;
writel ( val , clk - > en_reg ) ;
return 0 ;
}
static void generic_clk_disable ( struct clk * clk )
{
unsigned int val ;
if ( ! clk - > en_reg )
return ;
val = readl ( clk - > en_reg ) ;
if ( unlikely ( clk - > flags & RESET_TO_ENABLE ) )
val | = 1 < < clk - > en_reg_bit ;
else
val & = ~ ( 1 < < clk - > en_reg_bit ) ;
writel ( val , clk - > en_reg ) ;
}
/* generic clk ops */
static struct clkops generic_clkops = {
. enable = generic_clk_enable ,
. disable = generic_clk_disable ,
} ;
2011-02-16 07:40:39 +01:00
/* returns current programmed clocks clock info structure */
static struct pclk_info * pclk_info_get ( struct clk * clk )
{
unsigned int val , i ;
struct pclk_info * info = NULL ;
val = ( readl ( clk - > pclk_sel - > pclk_sel_reg ) > > clk - > pclk_sel_shift )
& clk - > pclk_sel - > pclk_sel_mask ;
for ( i = 0 ; i < clk - > pclk_sel - > pclk_count ; i + + ) {
if ( clk - > pclk_sel - > pclk_info [ i ] . pclk_val = = val )
info = & clk - > pclk_sel - > pclk_info [ i ] ;
}
return info ;
}
/*
* Set Update pclk , and pclk_info of clk and add clock sibling node to current
* parents children list
*/
static void clk_reparent ( struct clk * clk , struct pclk_info * pclk_info )
{
unsigned long flags ;
spin_lock_irqsave ( & clocks_lock , flags ) ;
list_del ( & clk - > sibling ) ;
list_add ( & clk - > sibling , & pclk_info - > pclk - > children ) ;
clk - > pclk = pclk_info - > pclk ;
spin_unlock_irqrestore ( & clocks_lock , flags ) ;
2011-02-16 07:40:40 +01:00
# ifdef CONFIG_DEBUG_FS
clk_debugfs_reparent ( clk ) ;
# endif
2011-02-16 07:40:39 +01:00
}
static void do_clk_disable ( struct clk * clk )
{
if ( ! clk )
return ;
if ( ! clk - > usage_count ) {
WARN_ON ( 1 ) ;
return ;
}
clk - > usage_count - - ;
if ( clk - > usage_count = = 0 ) {
/*
* Surely , there are no active childrens or direct users
* of this clock
*/
if ( clk - > pclk )
do_clk_disable ( clk - > pclk ) ;
if ( clk - > ops & & clk - > ops - > disable )
clk - > ops - > disable ( clk ) ;
}
}
static int do_clk_enable ( struct clk * clk )
{
int ret = 0 ;
if ( ! clk )
return - EFAULT ;
if ( clk - > usage_count = = 0 ) {
if ( clk - > pclk ) {
ret = do_clk_enable ( clk - > pclk ) ;
if ( ret )
goto err ;
}
if ( clk - > ops & & clk - > ops - > enable ) {
ret = clk - > ops - > enable ( clk ) ;
if ( ret ) {
if ( clk - > pclk )
do_clk_disable ( clk - > pclk ) ;
goto err ;
}
}
/*
* Since the clock is going to be used for the first
* time please reclac
*/
if ( clk - > recalc ) {
ret = clk - > recalc ( clk ) ;
if ( ret )
goto err ;
}
}
clk - > usage_count + + ;
err :
return ret ;
}
2010-04-01 12:30:46 +01:00
/*
* clk_enable - inform the system when the clock source should be running .
* @ clk : clock source
*
* If the clock can not be enabled / disabled , this should return success .
*
* Returns success ( 0 ) or negative errno .
*/
int clk_enable ( struct clk * clk )
{
unsigned long flags ;
int ret = 0 ;
spin_lock_irqsave ( & clocks_lock , flags ) ;
2011-02-16 07:40:39 +01:00
ret = do_clk_enable ( clk ) ;
2010-04-01 12:30:46 +01:00
spin_unlock_irqrestore ( & clocks_lock , flags ) ;
return ret ;
}
EXPORT_SYMBOL ( clk_enable ) ;
/*
* clk_disable - inform the system when the clock source is no longer required .
* @ clk : clock source
*
* Inform the system that a clock source is no longer required by
* a driver and may be shut down .
*
* Implementation detail : if the clock source is shared between
* multiple drivers , clk_enable ( ) calls must be balanced by the
* same number of clk_disable ( ) calls for the clock source to be
* disabled .
*/
void clk_disable ( struct clk * clk )
{
unsigned long flags ;
spin_lock_irqsave ( & clocks_lock , flags ) ;
2011-02-16 07:40:39 +01:00
do_clk_disable ( clk ) ;
2010-04-01 12:30:46 +01:00
spin_unlock_irqrestore ( & clocks_lock , flags ) ;
}
EXPORT_SYMBOL ( clk_disable ) ;
/**
* clk_get_rate - obtain the current clock rate ( in Hz ) for a clock source .
* This is only valid once the clock source has been enabled .
* @ clk : clock source
*/
unsigned long clk_get_rate ( struct clk * clk )
{
unsigned long flags , rate ;
spin_lock_irqsave ( & clocks_lock , flags ) ;
rate = clk - > rate ;
spin_unlock_irqrestore ( & clocks_lock , flags ) ;
return rate ;
}
EXPORT_SYMBOL ( clk_get_rate ) ;
/**
* clk_set_parent - set the parent clock source for this clock
* @ clk : clock source
* @ parent : parent clock source
*
* Returns success ( 0 ) or negative errno .
*/
int clk_set_parent ( struct clk * clk , struct clk * parent )
{
int i , found = 0 , val = 0 ;
unsigned long flags ;
2011-02-16 07:40:39 +01:00
if ( ! clk | | ! parent )
2010-04-01 12:30:46 +01:00
return - EFAULT ;
if ( clk - > pclk = = parent )
return 0 ;
2011-02-16 07:40:39 +01:00
if ( ! clk - > pclk_sel )
return - EPERM ;
2010-04-01 12:30:46 +01:00
2011-02-16 07:40:39 +01:00
/* check if requested parent is in clk parent list */
2010-04-01 12:30:46 +01:00
for ( i = 0 ; i < clk - > pclk_sel - > pclk_count ; i + + ) {
if ( clk - > pclk_sel - > pclk_info [ i ] . pclk = = parent ) {
found = 1 ;
break ;
}
}
if ( ! found )
return - EINVAL ;
spin_lock_irqsave ( & clocks_lock , flags ) ;
/* reflect parent change in hardware */
val = readl ( clk - > pclk_sel - > pclk_sel_reg ) ;
val & = ~ ( clk - > pclk_sel - > pclk_sel_mask < < clk - > pclk_sel_shift ) ;
2011-02-16 07:40:39 +01:00
val | = clk - > pclk_sel - > pclk_info [ i ] . pclk_val < < clk - > pclk_sel_shift ;
2010-04-01 12:30:46 +01:00
writel ( val , clk - > pclk_sel - > pclk_sel_reg ) ;
spin_unlock_irqrestore ( & clocks_lock , flags ) ;
/* reflect parent change in software */
2011-02-16 07:40:39 +01:00
clk_reparent ( clk , & clk - > pclk_sel - > pclk_info [ i ] ) ;
propagate_rate ( clk , 0 ) ;
2010-04-01 12:30:46 +01:00
return 0 ;
}
EXPORT_SYMBOL ( clk_set_parent ) ;
2011-02-16 07:40:31 +01:00
/**
* clk_set_rate - set the clock rate for a clock source
* @ clk : clock source
* @ rate : desired clock rate in Hz
*
* Returns success ( 0 ) or negative errno .
*/
int clk_set_rate ( struct clk * clk , unsigned long rate )
{
2011-02-16 07:40:39 +01:00
unsigned long flags ;
int ret = - EINVAL ;
if ( ! clk | | ! rate )
return - EFAULT ;
if ( clk - > set_rate ) {
spin_lock_irqsave ( & clocks_lock , flags ) ;
ret = clk - > set_rate ( clk , rate ) ;
if ( ! ret )
/* if successful -> propagate */
propagate_rate ( clk , 0 ) ;
spin_unlock_irqrestore ( & clocks_lock , flags ) ;
} else if ( clk - > pclk ) {
u32 mult = clk - > div_factor ? clk - > div_factor : 1 ;
ret = clk_set_rate ( clk - > pclk , mult * rate ) ;
}
return ret ;
2011-02-16 07:40:31 +01:00
}
EXPORT_SYMBOL ( clk_set_rate ) ;
2010-04-01 12:30:46 +01:00
/* registers clock in platform clock framework */
void clk_register ( struct clk_lookup * cl )
{
2011-02-16 07:40:39 +01:00
struct clk * clk ;
2010-04-01 12:30:46 +01:00
unsigned long flags ;
2011-02-16 07:40:39 +01:00
if ( ! cl | | ! cl - > clk )
2010-04-01 12:30:46 +01:00
return ;
2011-02-16 07:40:39 +01:00
clk = cl - > clk ;
2010-04-01 12:30:46 +01:00
spin_lock_irqsave ( & clocks_lock , flags ) ;
INIT_LIST_HEAD ( & clk - > children ) ;
if ( clk - > flags & ALWAYS_ENABLED )
clk - > ops = NULL ;
else if ( ! clk - > ops )
clk - > ops = & generic_clkops ;
/* root clock don't have any parents */
if ( ! clk - > pclk & & ! clk - > pclk_sel ) {
list_add ( & clk - > sibling , & root_clks ) ;
} else if ( clk - > pclk & & ! clk - > pclk_sel ) {
2011-02-16 07:40:39 +01:00
/* add clocks with only one parent to parent's children list */
2010-04-01 12:30:46 +01:00
list_add ( & clk - > sibling , & clk - > pclk - > children ) ;
} else {
2011-02-16 07:40:39 +01:00
/* clocks with more than one parent */
struct pclk_info * pclk_info ;
pclk_info = pclk_info_get ( clk ) ;
if ( ! pclk_info ) {
pr_err ( " CLKDEV: invalid pclk info of clk with "
" %s dev_id and %s con_id \n " ,
cl - > dev_id , cl - > con_id ) ;
} else {
clk - > pclk = pclk_info - > pclk ;
list_add ( & clk - > sibling , & pclk_info - > pclk - > children ) ;
}
2010-04-01 12:30:46 +01:00
}
2011-02-16 07:40:39 +01:00
2010-04-01 12:30:46 +01:00
spin_unlock_irqrestore ( & clocks_lock , flags ) ;
2011-02-16 07:40:40 +01:00
/* debugfs specific */
# ifdef CONFIG_DEBUG_FS
list_add ( & clk - > node , & clocks ) ;
clk - > cl = cl ;
# endif
2010-04-01 12:30:46 +01:00
/* add clock to arm clockdev framework */
clkdev_add ( cl ) ;
}
/**
2011-02-16 07:40:39 +01:00
* propagate_rate - recalculate and propagate all clocks to children
* @ pclk : parent clock required to be propogated
* @ on_init : flag for enabling clocks which are ENABLED_ON_INIT .
2010-04-01 12:30:46 +01:00
*
2011-02-16 07:40:39 +01:00
* Recalculates all children clocks
2010-04-01 12:30:46 +01:00
*/
2011-02-16 07:40:39 +01:00
void propagate_rate ( struct clk * pclk , int on_init )
2010-04-01 12:30:46 +01:00
{
2011-02-16 07:40:39 +01:00
struct clk * clk , * _temp ;
int ret = 0 ;
list_for_each_entry_safe ( clk , _temp , & pclk - > children , sibling ) {
if ( clk - > recalc ) {
ret = clk - > recalc ( clk ) ;
/*
* recalc will return error if clk out is not programmed
* In this case configure default rate .
*/
if ( ret & & clk - > set_rate )
clk - > set_rate ( clk , 0 ) ;
}
propagate_rate ( clk , on_init ) ;
if ( ! on_init )
continue ;
2010-04-01 12:30:46 +01:00
2011-02-16 07:40:39 +01:00
/* Enable clks enabled on init, in software view */
if ( clk - > flags & ENABLED_ON_INIT )
do_clk_enable ( clk ) ;
2010-04-01 12:30:46 +01:00
}
}
2011-02-16 07:40:39 +01:00
/**
* round_rate_index - return closest programmable rate index in rate_config tbl
* @ clk : ptr to clock structure
* @ drate : desired rate
* @ rate : final rate will be returned in this variable only .
*
* Finds index in rate_config for highest clk rate which is less than
* requested rate . If there is no clk rate lesser than requested rate then
* - EINVAL is returned . This routine assumes that rate_config is written
* in incrementing order of clk rates .
* If drate passed is zero then default rate is programmed .
*/
static int
round_rate_index ( struct clk * clk , unsigned long drate , unsigned long * rate )
2010-04-01 12:30:46 +01:00
{
2011-02-16 07:40:39 +01:00
unsigned long tmp = 0 , prev_rate = 0 ;
int index ;
2010-04-01 12:30:46 +01:00
2011-02-16 07:40:39 +01:00
if ( ! clk - > calc_rate )
return - EFAULT ;
2010-04-01 12:30:46 +01:00
2011-02-16 07:40:39 +01:00
if ( ! drate )
return - EINVAL ;
/*
* This loops ends on two conditions :
* - as soon as clk is found with rate greater than requested rate .
* - if all clks in rate_config are smaller than requested rate .
*/
for ( index = 0 ; index < clk - > rate_config . count ; index + + ) {
prev_rate = tmp ;
tmp = clk - > calc_rate ( clk , index ) ;
if ( drate < tmp ) {
index - - ;
break ;
}
2010-04-01 12:30:46 +01:00
}
2011-02-16 07:40:39 +01:00
/* return if can't find suitable clock */
if ( index < 0 ) {
index = - EINVAL ;
* rate = 0 ;
} else if ( index = = clk - > rate_config . count ) {
/* program with highest clk rate possible */
index = clk - > rate_config . count - 1 ;
* rate = tmp ;
} else
* rate = prev_rate ;
2010-04-01 12:30:46 +01:00
2011-02-16 07:40:39 +01:00
return index ;
2010-04-01 12:30:46 +01:00
}
2011-02-16 07:40:39 +01:00
/**
* clk_round_rate - adjust a rate to the exact rate a clock can provide
* @ clk : clock source
* @ rate : desired clock rate in Hz
*
* Returns rounded clock rate in Hz , or negative errno .
2010-04-01 12:30:46 +01:00
*/
2011-02-16 07:40:39 +01:00
long clk_round_rate ( struct clk * clk , unsigned long drate )
2010-04-01 12:30:46 +01:00
{
2011-02-16 07:40:39 +01:00
long rate = 0 ;
int index ;
/*
* propagate call to parent who supports calc_rate . Similar approach is
* used in clk_set_rate .
*/
if ( ! clk - > calc_rate ) {
u32 mult ;
if ( ! clk - > pclk )
return clk - > rate ;
mult = clk - > div_factor ? clk - > div_factor : 1 ;
return clk_round_rate ( clk - > pclk , mult * drate ) / mult ;
}
2010-04-01 12:30:46 +01:00
2011-02-16 07:40:39 +01:00
index = round_rate_index ( clk , drate , & rate ) ;
if ( index > = 0 )
return rate ;
else
return index ;
}
EXPORT_SYMBOL ( clk_round_rate ) ;
2010-04-01 12:30:46 +01:00
2011-02-16 07:40:39 +01:00
/*All below functions are called with lock held */
/*
* Calculates pll clk rate for specific value of mode , m , n and p
*
* In normal mode
* rate = ( 2 * M [ 15 : 8 ] * Fin ) / ( N * 2 ^ P )
*
* In Dithered mode
* rate = ( 2 * M [ 15 : 0 ] * Fin ) / ( 256 * N * 2 ^ P )
*/
unsigned long pll_calc_rate ( struct clk * clk , int index )
{
unsigned long rate = clk - > pclk - > rate ;
struct pll_rate_tbl * tbls = clk - > rate_config . tbls ;
unsigned int mode ;
mode = tbls [ index ] . mode ? 256 : 1 ;
return ( ( ( 2 * rate / 10000 ) * tbls [ index ] . m ) /
( mode * tbls [ index ] . n * ( 1 < < tbls [ index ] . p ) ) ) * 10000 ;
2010-04-01 12:30:46 +01:00
}
/*
* calculates current programmed rate of pll1
*
* In normal mode
* rate = ( 2 * M [ 15 : 8 ] * Fin ) / ( N * 2 ^ P )
*
* In Dithered mode
* rate = ( 2 * M [ 15 : 0 ] * Fin ) / ( 256 * N * 2 ^ P )
*/
2011-02-16 07:40:39 +01:00
int pll_clk_recalc ( struct clk * clk )
2010-04-01 12:30:46 +01:00
{
struct pll_clk_config * config = clk - > private_data ;
unsigned int num = 2 , den = 0 , val , mode = 0 ;
2011-02-16 07:40:31 +01:00
mode = ( readl ( config - > mode_reg ) > > config - > masks - > mode_shift ) &
config - > masks - > mode_mask ;
2010-04-01 12:30:46 +01:00
val = readl ( config - > cfg_reg ) ;
/* calculate denominator */
2011-02-16 07:40:31 +01:00
den = ( val > > config - > masks - > div_p_shift ) & config - > masks - > div_p_mask ;
2010-04-01 12:30:46 +01:00
den = 1 < < den ;
2011-02-16 07:40:31 +01:00
den * = ( val > > config - > masks - > div_n_shift ) & config - > masks - > div_n_mask ;
2010-04-01 12:30:46 +01:00
/* calculate numerator & denominator */
if ( ! mode ) {
/* Normal mode */
2011-02-16 07:40:31 +01:00
num * = ( val > > config - > masks - > norm_fdbk_m_shift ) &
config - > masks - > norm_fdbk_m_mask ;
2010-04-01 12:30:46 +01:00
} else {
/* Dithered mode */
2011-02-16 07:40:31 +01:00
num * = ( val > > config - > masks - > dith_fdbk_m_shift ) &
config - > masks - > dith_fdbk_m_mask ;
2010-04-01 12:30:46 +01:00
den * = 256 ;
}
2011-02-16 07:40:39 +01:00
if ( ! den )
return - EINVAL ;
2010-04-01 12:30:46 +01:00
clk - > rate = ( ( ( clk - > pclk - > rate / 10000 ) * num ) / den ) * 10000 ;
2011-02-16 07:40:39 +01:00
return 0 ;
}
/*
* Configures new clock rate of pll
*/
int pll_clk_set_rate ( struct clk * clk , unsigned long desired_rate )
{
struct pll_rate_tbl * tbls = clk - > rate_config . tbls ;
struct pll_clk_config * config = clk - > private_data ;
unsigned long val , rate ;
int i ;
i = round_rate_index ( clk , desired_rate , & rate ) ;
if ( i < 0 )
return i ;
val = readl ( config - > mode_reg ) &
~ ( config - > masks - > mode_mask < < config - > masks - > mode_shift ) ;
val | = ( tbls [ i ] . mode & config - > masks - > mode_mask ) < <
config - > masks - > mode_shift ;
writel ( val , config - > mode_reg ) ;
val = readl ( config - > cfg_reg ) &
~ ( config - > masks - > div_p_mask < < config - > masks - > div_p_shift ) ;
val | = ( tbls [ i ] . p & config - > masks - > div_p_mask ) < <
config - > masks - > div_p_shift ;
val & = ~ ( config - > masks - > div_n_mask < < config - > masks - > div_n_shift ) ;
val | = ( tbls [ i ] . n & config - > masks - > div_n_mask ) < <
config - > masks - > div_n_shift ;
val & = ~ ( config - > masks - > dith_fdbk_m_mask < <
config - > masks - > dith_fdbk_m_shift ) ;
if ( tbls [ i ] . mode )
val | = ( tbls [ i ] . m & config - > masks - > dith_fdbk_m_mask ) < <
config - > masks - > dith_fdbk_m_shift ;
else
val | = ( tbls [ i ] . m & config - > masks - > norm_fdbk_m_mask ) < <
config - > masks - > norm_fdbk_m_shift ;
writel ( val , config - > cfg_reg ) ;
clk - > rate = rate ;
return 0 ;
}
/*
* Calculates ahb , apb clk rate for specific value of div
*/
unsigned long bus_calc_rate ( struct clk * clk , int index )
{
unsigned long rate = clk - > pclk - > rate ;
struct bus_rate_tbl * tbls = clk - > rate_config . tbls ;
return rate / ( tbls [ index ] . div + 1 ) ;
2010-04-01 12:30:46 +01:00
}
/* calculates current programmed rate of ahb or apb bus */
2011-02-16 07:40:39 +01:00
int bus_clk_recalc ( struct clk * clk )
2010-04-01 12:30:46 +01:00
{
struct bus_clk_config * config = clk - > private_data ;
unsigned int div ;
2011-02-16 07:40:31 +01:00
div = ( ( readl ( config - > reg ) > > config - > masks - > shift ) &
config - > masks - > mask ) + 1 ;
2011-02-16 07:40:39 +01:00
if ( ! div )
return - EINVAL ;
2010-04-01 12:30:46 +01:00
clk - > rate = ( unsigned long ) clk - > pclk - > rate / div ;
2011-02-16 07:40:39 +01:00
return 0 ;
}
/* Configures new clock rate of AHB OR APB bus */
int bus_clk_set_rate ( struct clk * clk , unsigned long desired_rate )
{
struct bus_rate_tbl * tbls = clk - > rate_config . tbls ;
struct bus_clk_config * config = clk - > private_data ;
unsigned long val , rate ;
int i ;
i = round_rate_index ( clk , desired_rate , & rate ) ;
if ( i < 0 )
return i ;
val = readl ( config - > reg ) &
~ ( config - > masks - > mask < < config - > masks - > shift ) ;
val | = ( tbls [ i ] . div & config - > masks - > mask ) < < config - > masks - > shift ;
writel ( val , config - > reg ) ;
clk - > rate = rate ;
return 0 ;
}
/*
* gives rate for different values of eq , x and y
*
* Fout from synthesizer can be given from two equations :
* Fout1 = ( Fin * X / Y ) / 2 EQ1
* Fout2 = Fin * X / Y EQ2
*/
unsigned long aux_calc_rate ( struct clk * clk , int index )
{
unsigned long rate = clk - > pclk - > rate ;
struct aux_rate_tbl * tbls = clk - > rate_config . tbls ;
u8 eq = tbls [ index ] . eq ? 1 : 2 ;
return ( ( ( rate / 10000 ) * tbls [ index ] . xscale ) /
( tbls [ index ] . yscale * eq ) ) * 10000 ;
2010-04-01 12:30:46 +01:00
}
/*
* calculates current programmed rate of auxiliary synthesizers
* used by : UART , FIRDA
*
* Fout from synthesizer can be given from two equations :
* Fout1 = ( Fin * X / Y ) / 2
* Fout2 = Fin * X / Y
*
* Selection of eqn 1 or 2 is programmed in register
*/
2011-02-16 07:40:39 +01:00
int aux_clk_recalc ( struct clk * clk )
2010-04-01 12:30:46 +01:00
{
struct aux_clk_config * config = clk - > private_data ;
unsigned int num = 1 , den = 1 , val , eqn ;
2011-02-16 07:40:39 +01:00
val = readl ( config - > synth_reg ) ;
2010-04-01 12:30:46 +01:00
2011-02-16 07:40:39 +01:00
eqn = ( val > > config - > masks - > eq_sel_shift ) &
config - > masks - > eq_sel_mask ;
if ( eqn = = config - > masks - > eq1_mask )
den * = 2 ;
2010-04-01 12:30:46 +01:00
2011-02-16 07:40:39 +01:00
/* calculate numerator */
num = ( val > > config - > masks - > xscale_sel_shift ) &
config - > masks - > xscale_sel_mask ;
2010-04-01 12:30:46 +01:00
2011-02-16 07:40:39 +01:00
/* calculate denominator */
den * = ( val > > config - > masks - > yscale_sel_shift ) &
config - > masks - > yscale_sel_mask ;
if ( ! den )
return - EINVAL ;
clk - > rate = ( ( ( clk - > pclk - > rate / 10000 ) * num ) / den ) * 10000 ;
return 0 ;
}
/* Configures new clock rate of auxiliary synthesizers used by: UART, FIRDA*/
int aux_clk_set_rate ( struct clk * clk , unsigned long desired_rate )
{
struct aux_rate_tbl * tbls = clk - > rate_config . tbls ;
struct aux_clk_config * config = clk - > private_data ;
unsigned long val , rate ;
int i ;
i = round_rate_index ( clk , desired_rate , & rate ) ;
if ( i < 0 )
return i ;
val = readl ( config - > synth_reg ) &
~ ( config - > masks - > eq_sel_mask < < config - > masks - > eq_sel_shift ) ;
val | = ( tbls [ i ] . eq & config - > masks - > eq_sel_mask ) < <
config - > masks - > eq_sel_shift ;
val & = ~ ( config - > masks - > xscale_sel_mask < <
config - > masks - > xscale_sel_shift ) ;
val | = ( tbls [ i ] . xscale & config - > masks - > xscale_sel_mask ) < <
config - > masks - > xscale_sel_shift ;
val & = ~ ( config - > masks - > yscale_sel_mask < <
config - > masks - > yscale_sel_shift ) ;
val | = ( tbls [ i ] . yscale & config - > masks - > yscale_sel_mask ) < <
config - > masks - > yscale_sel_shift ;
writel ( val , config - > synth_reg ) ;
clk - > rate = rate ;
return 0 ;
}
/*
* Calculates gpt clk rate for different values of mscale and nscale
*
* Fout = Fin / ( ( 2 ^ ( N + 1 ) ) * ( M + 1 ) )
*/
unsigned long gpt_calc_rate ( struct clk * clk , int index )
{
unsigned long rate = clk - > pclk - > rate ;
struct gpt_rate_tbl * tbls = clk - > rate_config . tbls ;
return rate / ( ( 1 < < ( tbls [ index ] . nscale + 1 ) ) *
( tbls [ index ] . mscale + 1 ) ) ;
2010-04-01 12:30:46 +01:00
}
/*
* calculates current programmed rate of gpt synthesizers
* Fout from synthesizer can be given from below equations :
* Fout = Fin / ( ( 2 ^ ( N + 1 ) ) * ( M + 1 ) )
*/
2011-02-16 07:40:39 +01:00
int gpt_clk_recalc ( struct clk * clk )
2010-04-01 12:30:46 +01:00
{
2011-02-16 07:40:31 +01:00
struct gpt_clk_config * config = clk - > private_data ;
2010-04-01 12:30:46 +01:00
unsigned int div = 1 , val ;
2011-02-16 07:40:39 +01:00
val = readl ( config - > synth_reg ) ;
div + = ( val > > config - > masks - > mscale_sel_shift ) &
config - > masks - > mscale_sel_mask ;
div * = 1 < < ( ( ( val > > config - > masks - > nscale_sel_shift ) &
config - > masks - > nscale_sel_mask ) + 1 ) ;
2010-04-01 12:30:46 +01:00
2011-02-16 07:40:39 +01:00
if ( ! div )
return - EINVAL ;
2010-04-01 12:30:46 +01:00
clk - > rate = ( unsigned long ) clk - > pclk - > rate / div ;
2011-02-16 07:40:39 +01:00
return 0 ;
}
/* Configures new clock rate of gptiliary synthesizers used by: UART, FIRDA*/
int gpt_clk_set_rate ( struct clk * clk , unsigned long desired_rate )
{
struct gpt_rate_tbl * tbls = clk - > rate_config . tbls ;
struct gpt_clk_config * config = clk - > private_data ;
unsigned long val , rate ;
int i ;
i = round_rate_index ( clk , desired_rate , & rate ) ;
if ( i < 0 )
return i ;
val = readl ( config - > synth_reg ) & ~ ( config - > masks - > mscale_sel_mask < <
config - > masks - > mscale_sel_shift ) ;
val | = ( tbls [ i ] . mscale & config - > masks - > mscale_sel_mask ) < <
config - > masks - > mscale_sel_shift ;
val & = ~ ( config - > masks - > nscale_sel_mask < <
config - > masks - > nscale_sel_shift ) ;
val | = ( tbls [ i ] . nscale & config - > masks - > nscale_sel_mask ) < <
config - > masks - > nscale_sel_shift ;
writel ( val , config - > synth_reg ) ;
clk - > rate = rate ;
return 0 ;
}
/*
* Calculates clcd clk rate for different values of div
*
* Fout from synthesizer can be given from below equation :
* Fout = Fin / 2 * div ( division factor )
* div is 17 bits : -
* 0 - 13 ( fractional part )
* 14 - 16 ( integer part )
* To calculate Fout we left shift val by 14 bits and divide Fin by
* complete div ( including fractional part ) and then right shift the
* result by 14 places .
*/
unsigned long clcd_calc_rate ( struct clk * clk , int index )
{
unsigned long rate = clk - > pclk - > rate ;
struct clcd_rate_tbl * tbls = clk - > rate_config . tbls ;
rate / = 1000 ;
rate < < = 12 ;
rate / = ( 2 * tbls [ index ] . div ) ;
rate > > = 12 ;
rate * = 1000 ;
return rate ;
}
/*
* calculates current programmed rate of clcd synthesizer
* Fout from synthesizer can be given from below equation :
* Fout = Fin / 2 * div ( division factor )
* div is 17 bits : -
* 0 - 13 ( fractional part )
* 14 - 16 ( integer part )
* To calculate Fout we left shift val by 14 bits and divide Fin by
* complete div ( including fractional part ) and then right shift the
* result by 14 places .
*/
int clcd_clk_recalc ( struct clk * clk )
{
struct clcd_clk_config * config = clk - > private_data ;
unsigned int div = 1 ;
unsigned long prate ;
unsigned int val ;
val = readl ( config - > synth_reg ) ;
div = ( val > > config - > masks - > div_factor_shift ) &
config - > masks - > div_factor_mask ;
if ( ! div )
return - EINVAL ;
prate = clk - > pclk - > rate / 1000 ; /* first level division, make it KHz */
clk - > rate = ( ( ( unsigned long ) prate < < 12 ) / ( 2 * div ) ) > > 12 ;
clk - > rate * = 1000 ;
return 0 ;
}
/* Configures new clock rate of auxiliary synthesizers used by: UART, FIRDA*/
int clcd_clk_set_rate ( struct clk * clk , unsigned long desired_rate )
{
struct clcd_rate_tbl * tbls = clk - > rate_config . tbls ;
struct clcd_clk_config * config = clk - > private_data ;
unsigned long val , rate ;
int i ;
i = round_rate_index ( clk , desired_rate , & rate ) ;
if ( i < 0 )
return i ;
val = readl ( config - > synth_reg ) & ~ ( config - > masks - > div_factor_mask < <
config - > masks - > div_factor_shift ) ;
val | = ( tbls [ i ] . div & config - > masks - > div_factor_mask ) < <
config - > masks - > div_factor_shift ;
writel ( val , config - > synth_reg ) ;
clk - > rate = rate ;
return 0 ;
2010-04-01 12:30:46 +01:00
}
/*
2011-02-16 07:40:31 +01:00
* Used for clocks that always have value as the parent clock divided by a
2010-04-01 12:30:46 +01:00
* fixed divisor
*/
2011-02-16 07:40:39 +01:00
int follow_parent ( struct clk * clk )
2010-04-01 12:30:46 +01:00
{
2011-02-16 07:40:31 +01:00
unsigned int div_factor = ( clk - > div_factor < 1 ) ? 1 : clk - > div_factor ;
2010-04-01 12:30:46 +01:00
2011-02-16 07:40:31 +01:00
clk - > rate = clk - > pclk - > rate / div_factor ;
2011-02-16 07:40:39 +01:00
return 0 ;
2010-04-01 12:30:46 +01:00
}
/**
* recalc_root_clocks - recalculate and propagate all root clocks
*
* Recalculates all root clocks ( clocks with no parent ) , which if the
* clock ' s . recalc is set correctly , should also propagate their rates .
*/
void recalc_root_clocks ( void )
{
2011-02-16 07:40:39 +01:00
struct clk * pclk ;
unsigned long flags ;
int ret = 0 ;
spin_lock_irqsave ( & clocks_lock , flags ) ;
list_for_each_entry ( pclk , & root_clks , sibling ) {
if ( pclk - > recalc ) {
ret = pclk - > recalc ( pclk ) ;
/*
* recalc will return error if clk out is not programmed
* In this case configure default clock .
*/
if ( ret & & pclk - > set_rate )
pclk - > set_rate ( pclk , 0 ) ;
}
propagate_rate ( pclk , 1 ) ;
/* Enable clks enabled on init, in software view */
if ( pclk - > flags & ENABLED_ON_INIT )
do_clk_enable ( pclk ) ;
}
spin_unlock_irqrestore ( & clocks_lock , flags ) ;
2010-04-01 12:30:46 +01:00
}
2011-02-16 07:40:40 +01:00
2011-05-20 08:34:18 +01:00
void __init clk_init ( void )
{
recalc_root_clocks ( ) ;
}
2011-02-16 07:40:40 +01:00
# ifdef CONFIG_DEBUG_FS
/*
* debugfs support to trace clock tree hierarchy and attributes
*/
static struct dentry * clk_debugfs_root ;
static int clk_debugfs_register_one ( struct clk * c )
{
int err ;
2011-07-16 12:37:57 -04:00
struct dentry * d ;
2011-02-16 07:40:40 +01:00
struct clk * pa = c - > pclk ;
char s [ 255 ] ;
char * p = s ;
if ( c ) {
if ( c - > cl - > con_id )
p + = sprintf ( p , " %s " , c - > cl - > con_id ) ;
if ( c - > cl - > dev_id )
p + = sprintf ( p , " %s " , c - > cl - > dev_id ) ;
}
d = debugfs_create_dir ( s , pa ? pa - > dent : clk_debugfs_root ) ;
if ( ! d )
return - ENOMEM ;
c - > dent = d ;
d = debugfs_create_u32 ( " usage_count " , S_IRUGO , c - > dent ,
( u32 * ) & c - > usage_count ) ;
if ( ! d ) {
err = - ENOMEM ;
goto err_out ;
}
d = debugfs_create_u32 ( " rate " , S_IRUGO , c - > dent , ( u32 * ) & c - > rate ) ;
if ( ! d ) {
err = - ENOMEM ;
goto err_out ;
}
d = debugfs_create_x32 ( " flags " , S_IRUGO , c - > dent , ( u32 * ) & c - > flags ) ;
if ( ! d ) {
err = - ENOMEM ;
goto err_out ;
}
return 0 ;
err_out :
2011-07-16 12:37:57 -04:00
debugfs_remove_recursive ( c - > dent ) ;
2011-02-16 07:40:40 +01:00
return err ;
}
static int clk_debugfs_register ( struct clk * c )
{
int err ;
struct clk * pa = c - > pclk ;
if ( pa & & ! pa - > dent ) {
err = clk_debugfs_register ( pa ) ;
if ( err )
return err ;
}
if ( ! c - > dent ) {
err = clk_debugfs_register_one ( c ) ;
if ( err )
return err ;
}
return 0 ;
}
static int __init clk_debugfs_init ( void )
{
struct clk * c ;
struct dentry * d ;
int err ;
d = debugfs_create_dir ( " clock " , NULL ) ;
if ( ! d )
return - ENOMEM ;
clk_debugfs_root = d ;
list_for_each_entry ( c , & clocks , node ) {
err = clk_debugfs_register ( c ) ;
if ( err )
goto err_out ;
}
return 0 ;
err_out :
debugfs_remove_recursive ( clk_debugfs_root ) ;
return err ;
}
late_initcall ( clk_debugfs_init ) ;
static int clk_debugfs_reparent ( struct clk * c )
{
debugfs_remove ( c - > dent ) ;
return clk_debugfs_register_one ( c ) ;
}
# endif /* CONFIG_DEBUG_FS */