2010-01-27 06:13:04 +03:00
/*
* clkt_clksel . c - OMAP2 / 3 / 4 clksel clock functions
*
* Copyright ( C ) 2005 - 2008 Texas Instruments , Inc .
* Copyright ( C ) 2004 - 2010 Nokia Corporation
*
* Contacts :
* Richard Woodruff < r - woodruff2 @ ti . com >
* Paul Walmsley
*
* 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 .
*
2010-05-19 04:40:24 +04:00
*
* clksel clocks are clocks that do not have a fixed parent , or that
* can divide their parent ' s rate , or possibly both at the same time , based
* on the contents of a hardware register bitfield .
*
* All of the various mux and divider settings can be encoded into
* struct clksel * data structures , and then these can be autogenerated
* from some hardware database for each new chip generation . This
* should avoid the need to write , review , and validate a lot of new
* clock code for each new chip , since it can be exported from the SoC
* design flow . This is now done on OMAP4 .
*
* The fusion of mux and divider clocks is a software creation . In
* hardware reality , the multiplexer ( parent selection ) and the
* divider exist separately . XXX At some point these clksel clocks
* should be split into " divider " clocks and " mux " clocks to better
* match the hardware .
*
* ( The name " clksel " comes from the name of the corresponding
* register field in the OMAP2 / 3 family of SoCs . )
2010-01-27 06:13:04 +03:00
*
* XXX Currently these clocks are only used in the OMAP2 / 3 / 4 code , but
* many of the OMAP1 clocks should be convertible to use this
* mechanism .
*/
# undef DEBUG
# include <linux/kernel.h>
# include <linux/errno.h>
# include <linux/clk.h>
# include <linux/io.h>
2012-03-08 05:28:01 +04:00
# include <linux/bug.h>
2010-01-27 06:13:04 +03:00
# include <plat/clock.h>
# include "clock.h"
/* Private functions */
/**
2010-05-19 04:40:24 +04:00
* _get_clksel_by_parent ( ) - return clksel struct for a given clk & parent
2010-01-27 06:13:04 +03:00
* @ clk : OMAP struct clk ptr to inspect
* @ src_clk : OMAP struct clk ptr of the parent clk to search for
*
* Scan the struct clksel array associated with the clock to find
* the element associated with the supplied parent clock address .
* Returns a pointer to the struct clksel on success or NULL on error .
*/
2010-05-19 04:40:24 +04:00
static const struct clksel * _get_clksel_by_parent ( struct clk * clk ,
struct clk * src_clk )
2010-01-27 06:13:04 +03:00
{
const struct clksel * clks ;
2010-05-19 04:40:24 +04:00
for ( clks = clk - > clksel ; clks - > parent ; clks + + )
2010-01-27 06:13:04 +03:00
if ( clks - > parent = = src_clk )
break ; /* Found the requested parent */
if ( ! clks - > parent ) {
2010-05-19 04:40:24 +04:00
/* This indicates a data problem */
2012-09-22 12:24:17 +04:00
WARN ( 1 , " clock: %s: could not find parent clock %s in clksel array \n " ,
__clk_get_name ( clk ) , __clk_get_name ( src_clk ) ) ;
2010-01-27 06:13:04 +03:00
return NULL ;
}
return clks ;
}
2010-05-19 04:40:24 +04:00
/**
2010-05-19 04:40:24 +04:00
* _get_div_and_fieldval ( ) - find the new clksel divisor and field value to use
2010-05-19 04:40:24 +04:00
* @ src_clk : planned new parent struct clk *
* @ clk : struct clk * that is being reparented
* @ field_val : pointer to a u32 to contain the register data for the divisor
*
* Given an intended new parent struct clk * @ src_clk , and the struct
* clk * @ clk to the clock that is being reparented , find the
* appropriate rate divisor for the new clock ( returned as the return
* value ) , and the corresponding register bitfield data to program to
* reach that divisor ( returned in the u32 pointed to by @ field_val ) .
* Returns 0 on error , or returns the newly - selected divisor upon
* success ( in this latter case , the corresponding register bitfield
* value is passed back in the variable pointed to by @ field_val )
2010-01-27 06:13:04 +03:00
*/
2010-05-19 04:40:24 +04:00
static u8 _get_div_and_fieldval ( struct clk * src_clk , struct clk * clk ,
u32 * field_val )
2010-01-27 06:13:04 +03:00
{
const struct clksel * clks ;
2011-01-16 14:22:03 +03:00
const struct clksel_rate * clkr , * max_clkr = NULL ;
2010-05-19 04:40:24 +04:00
u8 max_div = 0 ;
2010-01-27 06:13:04 +03:00
2010-05-19 04:40:24 +04:00
clks = _get_clksel_by_parent ( clk , src_clk ) ;
2010-01-27 06:13:04 +03:00
if ( ! clks )
return 0 ;
2010-05-19 04:40:24 +04:00
/*
* Find the highest divisor ( e . g . , the one resulting in the
* lowest rate ) to use as the default . This should avoid
* clock rates that are too high for the device . XXX A better
* solution here would be to try to determine if there is a
* divisor matching the original clock rate before the parent
* switch , and if it cannot be found , to fall back to the
* highest divisor .
*/
2010-01-27 06:13:04 +03:00
for ( clkr = clks - > rates ; clkr - > div ; clkr + + ) {
2010-05-19 04:40:24 +04:00
if ( ! ( clkr - > flags & cpu_mask ) )
continue ;
if ( clkr - > div > max_div ) {
max_div = clkr - > div ;
max_clkr = clkr ;
}
2010-01-27 06:13:04 +03:00
}
2010-05-19 04:40:24 +04:00
if ( max_div = = 0 ) {
2010-05-19 04:40:24 +04:00
/* This indicates an error in the clksel data */
2012-09-22 12:24:17 +04:00
WARN ( 1 , " clock: %s: could not find divisor for parent %s \n " ,
__clk_get_name ( clk ) ,
__clk_get_name ( __clk_get_parent ( src_clk ) ) ) ;
2010-01-27 06:13:04 +03:00
return 0 ;
}
2010-05-19 04:40:24 +04:00
* field_val = max_clkr - > val ;
2010-01-27 06:13:04 +03:00
2010-05-19 04:40:24 +04:00
return max_div ;
2010-01-27 06:13:04 +03:00
}
2010-05-19 04:40:24 +04:00
/**
* _write_clksel_reg ( ) - program a clock ' s clksel register in hardware
* @ clk : struct clk * to program
* @ v : clksel bitfield value to program ( with LSB at bit 0 )
*
* Shift the clksel register bitfield value @ v to its appropriate
* location in the clksel register and write it in . This function
* will ensure that the write to the clksel_reg reaches its
* destination before returning - - important since PRM and CM register
* accesses can be quite slow compared to ARM cycles - - but does not
* take into account any time the hardware might take to switch the
* clock source .
*/
static void _write_clksel_reg ( struct clk * clk , u32 field_val )
{
u32 v ;
2010-01-27 06:13:04 +03:00
2010-05-19 04:40:24 +04:00
v = __raw_readl ( clk - > clksel_reg ) ;
v & = ~ clk - > clksel_mask ;
v | = field_val < < __ffs ( clk - > clksel_mask ) ;
__raw_writel ( v , clk - > clksel_reg ) ;
v = __raw_readl ( clk - > clksel_reg ) ; /* OCP barrier */
}
2010-01-27 06:13:04 +03:00
/**
2010-05-19 04:40:24 +04:00
* _clksel_to_divisor ( ) - turn clksel field value into integer divider
* @ clk : OMAP struct clk to use
* @ field_val : register field value to find
2010-01-27 06:13:04 +03:00
*
2010-05-19 04:40:24 +04:00
* Given a struct clk of a rate - selectable clksel clock , and a register field
* value to search for , find the corresponding clock divisor . The register
* field value should be pre - masked and shifted down so the LSB is at bit 0
* before calling . Returns 0 on error or returns the actual integer divisor
* upon success .
2010-01-27 06:13:04 +03:00
*/
2010-05-19 04:40:24 +04:00
static u32 _clksel_to_divisor ( struct clk * clk , u32 field_val )
2010-01-27 06:13:04 +03:00
{
const struct clksel * clks ;
const struct clksel_rate * clkr ;
2012-09-22 12:24:17 +04:00
struct clk * parent ;
2010-01-27 06:13:04 +03:00
2012-09-22 12:24:17 +04:00
parent = __clk_get_parent ( clk ) ;
clks = _get_clksel_by_parent ( clk , parent ) ;
2010-05-19 04:40:24 +04:00
if ( ! clks )
return 0 ;
2010-01-27 06:13:04 +03:00
2010-05-19 04:40:24 +04:00
for ( clkr = clks - > rates ; clkr - > div ; clkr + + ) {
if ( ! ( clkr - > flags & cpu_mask ) )
continue ;
2010-01-27 06:13:04 +03:00
2010-05-19 04:40:24 +04:00
if ( clkr - > val = = field_val )
break ;
2010-01-27 06:13:04 +03:00
}
2010-05-19 04:40:24 +04:00
if ( ! clkr - > div ) {
/* This indicates a data error */
2012-09-22 12:24:17 +04:00
WARN ( 1 , " clock: %s: could not find fieldval %d for parent %s \n " ,
__clk_get_name ( clk ) , field_val , __clk_get_name ( parent ) ) ;
2010-05-19 04:40:24 +04:00
return 0 ;
}
2010-01-27 06:13:04 +03:00
2010-05-19 04:40:24 +04:00
return clkr - > div ;
2010-01-27 06:13:04 +03:00
}
2010-05-19 04:40:24 +04:00
/**
* _divisor_to_clksel ( ) - turn clksel integer divisor into a field value
* @ clk : OMAP struct clk to use
* @ div : integer divisor to search for
*
* Given a struct clk of a rate - selectable clksel clock , and a clock
* divisor , find the corresponding register field value . Returns the
* register field value _before_ left - shifting ( i . e . , LSB is at bit
* 0 ) ; or returns 0xFFFFFFFF ( ~ 0 ) upon error .
2010-01-27 06:13:04 +03:00
*/
2010-05-19 04:40:24 +04:00
static u32 _divisor_to_clksel ( struct clk * clk , u32 div )
2010-01-27 06:13:04 +03:00
{
2010-05-19 04:40:24 +04:00
const struct clksel * clks ;
const struct clksel_rate * clkr ;
2012-09-22 12:24:17 +04:00
struct clk * parent ;
2010-01-27 06:13:04 +03:00
2010-05-19 04:40:24 +04:00
/* should never happen */
WARN_ON ( div = = 0 ) ;
2010-01-27 06:13:04 +03:00
2012-09-22 12:24:17 +04:00
parent = __clk_get_parent ( clk ) ;
clks = _get_clksel_by_parent ( clk , parent ) ;
2010-05-19 04:40:24 +04:00
if ( ! clks )
return ~ 0 ;
2010-01-27 06:13:04 +03:00
2010-05-19 04:40:24 +04:00
for ( clkr = clks - > rates ; clkr - > div ; clkr + + ) {
if ( ! ( clkr - > flags & cpu_mask ) )
continue ;
2010-01-27 06:13:04 +03:00
2010-05-19 04:40:24 +04:00
if ( clkr - > div = = div )
break ;
}
2010-01-27 06:13:04 +03:00
2010-05-19 04:40:24 +04:00
if ( ! clkr - > div ) {
2012-09-22 12:24:17 +04:00
pr_err ( " clock: %s: could not find divisor %d for parent %s \n " ,
__clk_get_name ( clk ) , div , __clk_get_name ( parent ) ) ;
2010-05-19 04:40:24 +04:00
return ~ 0 ;
}
return clkr - > val ;
2010-01-27 06:13:04 +03:00
}
/**
2010-05-19 04:40:24 +04:00
* _read_divisor ( ) - get current divisor applied to parent clock ( from hdwr )
* @ clk : OMAP struct clk to use .
*
* Read the current divisor register value for @ clk that is programmed
* into the hardware , convert it into the actual divisor value , and
* return it ; or return 0 on error .
*/
static u32 _read_divisor ( struct clk * clk )
{
u32 v ;
if ( ! clk - > clksel | | ! clk - > clksel_mask )
return 0 ;
v = __raw_readl ( clk - > clksel_reg ) ;
v & = clk - > clksel_mask ;
v > > = __ffs ( clk - > clksel_mask ) ;
return _clksel_to_divisor ( clk , v ) ;
}
/* Public functions */
/**
* omap2_clksel_round_rate_div ( ) - find divisor for the given clock and rate
2010-01-27 06:13:04 +03:00
* @ clk : OMAP struct clk to use
* @ target_rate : desired clock rate
* @ new_div : ptr to where we should store the divisor
*
* Finds ' best ' divider value in an array based on the source and target
* rates . The divider array must be sorted with smallest divider first .
2010-05-19 04:40:24 +04:00
* This function is also used by the DPLL3 M2 divider code .
2010-01-27 06:13:04 +03:00
*
* Returns the rounded clock rate or returns 0xffffffff on error .
*/
u32 omap2_clksel_round_rate_div ( struct clk * clk , unsigned long target_rate ,
u32 * new_div )
{
unsigned long test_rate ;
const struct clksel * clks ;
const struct clksel_rate * clkr ;
u32 last_div = 0 ;
2012-09-22 12:24:17 +04:00
struct clk * parent ;
unsigned long parent_rate ;
const char * clk_name ;
parent = __clk_get_parent ( clk ) ;
parent_rate = __clk_get_rate ( parent ) ;
clk_name = __clk_get_name ( clk ) ;
2010-01-27 06:13:04 +03:00
2010-05-19 04:40:24 +04:00
if ( ! clk - > clksel | | ! clk - > clksel_mask )
return ~ 0 ;
2010-01-27 06:13:04 +03:00
pr_debug ( " clock: clksel_round_rate_div: %s target_rate %ld \n " ,
2012-09-22 12:24:17 +04:00
clk_name , target_rate ) ;
2010-01-27 06:13:04 +03:00
* new_div = 1 ;
2012-09-22 12:24:17 +04:00
clks = _get_clksel_by_parent ( clk , parent ) ;
2010-01-27 06:13:04 +03:00
if ( ! clks )
return ~ 0 ;
for ( clkr = clks - > rates ; clkr - > div ; clkr + + ) {
if ( ! ( clkr - > flags & cpu_mask ) )
continue ;
/* Sanity check */
if ( clkr - > div < = last_div )
2012-09-22 12:24:17 +04:00
pr_err ( " clock: %s: clksel_rate table not sorted \n " ,
clk_name ) ;
2010-01-27 06:13:04 +03:00
last_div = clkr - > div ;
2012-09-22 12:24:17 +04:00
test_rate = parent_rate / clkr - > div ;
2010-01-27 06:13:04 +03:00
if ( test_rate < = target_rate )
break ; /* found it */
}
if ( ! clkr - > div ) {
2012-09-22 12:24:17 +04:00
pr_err ( " clock: %s: could not find divisor for target rate %ld for parent %s \n " ,
clk_name , target_rate , __clk_get_name ( parent ) ) ;
2010-01-27 06:13:04 +03:00
return ~ 0 ;
}
* new_div = clkr - > div ;
pr_debug ( " clock: new_div = %d, new_rate = %ld \n " , * new_div ,
2012-09-22 12:24:17 +04:00
( parent_rate / clkr - > div ) ) ;
2010-01-27 06:13:04 +03:00
2012-09-22 12:24:17 +04:00
return parent_rate / clkr - > div ;
2010-01-27 06:13:04 +03:00
}
2010-05-19 04:40:24 +04:00
/*
* Clocktype interface functions to the OMAP clock code
* ( i . e . , those used in struct clk field function pointers , etc . )
2010-01-27 06:13:04 +03:00
*/
/**
2010-05-19 04:40:24 +04:00
* omap2_init_clksel_parent ( ) - set a clksel clk ' s parent field from the hdwr
* @ clk : OMAP clock struct ptr to use
2010-01-27 06:13:04 +03:00
*
2010-05-19 04:40:24 +04:00
* Given a pointer @ clk to a source - selectable struct clk , read the
* hardware register and determine what its parent is currently set
* to . Update @ clk ' s . parent field with the appropriate clk ptr . No
* return value .
2010-01-27 06:13:04 +03:00
*/
2010-05-19 04:40:24 +04:00
void omap2_init_clksel_parent ( struct clk * clk )
2010-01-27 06:13:04 +03:00
{
const struct clksel * clks ;
const struct clksel_rate * clkr ;
2010-05-19 04:40:24 +04:00
u32 r , found = 0 ;
2012-09-22 12:24:17 +04:00
struct clk * parent ;
const char * clk_name ;
2010-01-27 06:13:04 +03:00
2010-05-19 04:40:24 +04:00
if ( ! clk - > clksel | | ! clk - > clksel_mask )
return ;
2010-01-27 06:13:04 +03:00
2012-09-22 12:24:17 +04:00
parent = __clk_get_parent ( clk ) ;
clk_name = __clk_get_name ( clk ) ;
2010-05-19 04:40:24 +04:00
r = __raw_readl ( clk - > clksel_reg ) & clk - > clksel_mask ;
r > > = __ffs ( clk - > clksel_mask ) ;
2010-01-27 06:13:04 +03:00
2010-05-19 04:40:24 +04:00
for ( clks = clk - > clksel ; clks - > parent & & ! found ; clks + + ) {
for ( clkr = clks - > rates ; clkr - > div & & ! found ; clkr + + ) {
if ( ! ( clkr - > flags & cpu_mask ) )
continue ;
if ( clkr - > val = = r ) {
2012-09-22 12:24:17 +04:00
if ( parent ! = clks - > parent ) {
2010-05-19 04:40:24 +04:00
pr_debug ( " clock: inited %s parent "
" to %s (was %s) \n " ,
2012-09-22 12:24:17 +04:00
clk_name ,
__clk_get_name ( clks - > parent ) ,
( ( parent ) ?
__clk_get_name ( parent ) :
" NULL " ) ) ;
2010-05-19 04:40:24 +04:00
clk_reparent ( clk , clks - > parent ) ;
} ;
found = 1 ;
}
}
2010-01-27 06:13:04 +03:00
}
2010-05-19 04:40:24 +04:00
/* This indicates a data error */
WARN ( ! found , " clock: %s: init parent: could not find regval %0x \n " ,
2012-09-22 12:24:17 +04:00
clk_name , r ) ;
2010-05-19 04:40:24 +04:00
return ;
2010-01-27 06:13:04 +03:00
}
/**
2010-05-19 04:40:24 +04:00
* omap2_clksel_recalc ( ) - function ptr to pass via struct clk . recalc field
* @ clk : struct clk *
2010-01-27 06:13:04 +03:00
*
2010-05-19 04:40:24 +04:00
* This function is intended to be called only by the clock framework .
* Each clksel clock should have its struct clk . recalc field set to this
* function . Returns the clock ' s current rate , based on its parent ' s rate
* and its current divisor setting in the hardware .
2010-01-27 06:13:04 +03:00
*/
2010-05-19 04:40:24 +04:00
unsigned long omap2_clksel_recalc ( struct clk * clk )
2010-01-27 06:13:04 +03:00
{
2010-05-19 04:40:24 +04:00
unsigned long rate ;
u32 div = 0 ;
2012-09-22 12:24:17 +04:00
struct clk * parent ;
2010-01-27 06:13:04 +03:00
2010-05-19 04:40:24 +04:00
div = _read_divisor ( clk ) ;
if ( div = = 0 )
2012-09-22 12:24:17 +04:00
return __clk_get_rate ( clk ) ;
2010-01-27 06:13:04 +03:00
2012-09-22 12:24:17 +04:00
parent = __clk_get_parent ( clk ) ;
rate = __clk_get_rate ( parent ) / div ;
2010-01-27 06:13:04 +03:00
2012-09-22 12:24:17 +04:00
pr_debug ( " clock: %s: recalc'd rate is %ld (div %d) \n " ,
__clk_get_name ( clk ) , rate , div ) ;
2010-01-27 06:13:04 +03:00
2010-05-19 04:40:24 +04:00
return rate ;
2010-01-27 06:13:04 +03:00
}
/**
2010-05-19 04:40:24 +04:00
* omap2_clksel_round_rate ( ) - find rounded rate for the given clock and rate
* @ clk : OMAP struct clk to use
* @ target_rate : desired clock rate
*
* This function is intended to be called only by the clock framework .
* Finds best target rate based on the source clock and possible dividers .
* rates . The divider array must be sorted with smallest divider first .
2010-01-27 06:13:04 +03:00
*
2010-05-19 04:40:24 +04:00
* Returns the rounded clock rate or returns 0xffffffff on error .
2010-01-27 06:13:04 +03:00
*/
2010-05-19 04:40:24 +04:00
long omap2_clksel_round_rate ( struct clk * clk , unsigned long target_rate )
2010-01-27 06:13:04 +03:00
{
2010-05-19 04:40:24 +04:00
u32 new_div ;
2010-01-27 06:13:04 +03:00
2010-05-19 04:40:24 +04:00
return omap2_clksel_round_rate_div ( clk , target_rate , & new_div ) ;
2010-01-27 06:13:04 +03:00
}
2010-05-19 04:40:24 +04:00
/**
* omap2_clksel_set_rate ( ) - program clock rate in hardware
* @ clk : struct clk * to program rate
* @ rate : target rate to program
*
* This function is intended to be called only by the clock framework .
* Program @ clk ' s rate to @ rate in the hardware . The clock can be
* either enabled or disabled when this happens , although if the clock
* is enabled , some downstream devices may glitch or behave
* unpredictably when the clock rate is changed - this depends on the
* hardware . This function does not currently check the usecount of
* the clock , so if multiple drivers are using the clock , and the rate
* is changed , they will all be affected without any notification .
* Returns - EINVAL upon error , or 0 upon success .
*/
2010-01-27 06:13:04 +03:00
int omap2_clksel_set_rate ( struct clk * clk , unsigned long rate )
{
2010-05-19 04:40:24 +04:00
u32 field_val , validrate , new_div = 0 ;
2010-01-27 06:13:04 +03:00
2010-05-19 04:40:24 +04:00
if ( ! clk - > clksel | | ! clk - > clksel_mask )
2010-01-27 06:13:04 +03:00
return - EINVAL ;
validrate = omap2_clksel_round_rate_div ( clk , rate , & new_div ) ;
if ( validrate ! = rate )
return - EINVAL ;
2010-05-19 04:40:24 +04:00
field_val = _divisor_to_clksel ( clk , new_div ) ;
2010-01-27 06:13:04 +03:00
if ( field_val = = ~ 0 )
return - EINVAL ;
2010-05-19 04:40:24 +04:00
_write_clksel_reg ( clk , field_val ) ;
2010-01-27 06:13:04 +03:00
2012-09-22 12:24:17 +04:00
clk - > rate = __clk_get_rate ( __clk_get_parent ( clk ) ) / new_div ;
2010-01-27 06:13:04 +03:00
2012-09-22 12:24:17 +04:00
pr_debug ( " clock: %s: set rate to %ld \n " , __clk_get_name ( clk ) ,
__clk_get_rate ( clk ) ) ;
2010-05-19 04:40:24 +04:00
2010-01-27 06:13:04 +03:00
return 0 ;
}
2010-05-19 04:40:24 +04:00
/*
* Clksel parent setting function - not passed in struct clk function
* pointer - instead , the OMAP clock code currently assumes that any
* parent - setting clock is a clksel clock , and calls
* omap2_clksel_set_parent ( ) by default
*/
/**
* omap2_clksel_set_parent ( ) - change a clock ' s parent clock
* @ clk : struct clk * of the child clock
* @ new_parent : struct clk * of the new parent clock
*
* This function is intended to be called only by the clock framework .
* Change the parent clock of clock @ clk to @ new_parent . This is
* intended to be used while @ clk is disabled . This function does not
* currently check the usecount of the clock , so if multiple drivers
* are using the clock , and the parent is changed , they will all be
* affected without any notification . Returns - EINVAL upon error , or
* 0 upon success .
*/
2010-01-27 06:13:04 +03:00
int omap2_clksel_set_parent ( struct clk * clk , struct clk * new_parent )
{
2010-05-19 04:40:24 +04:00
u32 field_val = 0 ;
u32 parent_div ;
2010-01-27 06:13:04 +03:00
2010-05-19 04:40:24 +04:00
if ( ! clk - > clksel | | ! clk - > clksel_mask )
2010-01-27 06:13:04 +03:00
return - EINVAL ;
2010-05-19 04:40:24 +04:00
parent_div = _get_div_and_fieldval ( new_parent , clk , & field_val ) ;
2010-01-27 06:13:04 +03:00
if ( ! parent_div )
return - EINVAL ;
2010-05-19 04:40:24 +04:00
_write_clksel_reg ( clk , field_val ) ;
2010-01-27 06:13:04 +03:00
clk_reparent ( clk , new_parent ) ;
/* CLKSEL clocks follow their parents' rates, divided by a divisor */
2012-09-22 12:24:17 +04:00
clk - > rate = __clk_get_rate ( new_parent ) ;
2010-01-27 06:13:04 +03:00
if ( parent_div > 0 )
2012-09-22 12:24:17 +04:00
__clk_get_rate ( clk ) / = parent_div ;
2010-01-27 06:13:04 +03:00
2010-05-19 04:40:24 +04:00
pr_debug ( " clock: %s: set parent to %s (new rate %ld) \n " ,
2012-09-22 12:24:17 +04:00
__clk_get_name ( clk ) ,
__clk_get_name ( __clk_get_parent ( clk ) ) ,
__clk_get_rate ( clk ) ) ;
2010-01-27 06:13:04 +03:00
return 0 ;
}