davinci: make clock rate re-calculation easy

Make clock rate recalculation easy by having a re-calculate
function for each clock.

The existing functions for calculation of output rates of PLL
and PLL-derived sysclks have been convered to the new
re-calculate API.

A new function is introduced to take care of rate
(re)calculation for leaf clocks.

Signed-off-by: Sekhar Nori <nsekhar@ti.com>
Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
This commit is contained in:
Sekhar Nori 2009-08-31 15:48:02 +05:30 committed by Kevin Hilman
parent f02bf3b396
commit de381a91f5
2 changed files with 50 additions and 20 deletions

View file

@ -135,8 +135,12 @@ int clk_register(struct clk *clk)
if (clk->rate)
return 0;
/* Else, see if there is a way to calculate it */
if (clk->recalc)
clk->rate = clk->recalc(clk);
/* Otherwise, default to parent rate */
if (clk->parent)
else if (clk->parent)
clk->rate = clk->parent->rate;
return 0;
@ -184,50 +188,62 @@ static int __init clk_disable_unused(void)
late_initcall(clk_disable_unused);
#endif
static void clk_sysclk_recalc(struct clk *clk)
static unsigned long clk_sysclk_recalc(struct clk *clk)
{
u32 v, plldiv;
struct pll_data *pll;
unsigned long rate = clk->rate;
/* If this is the PLL base clock, no more calculations needed */
if (clk->pll_data)
return;
return rate;
if (WARN_ON(!clk->parent))
return;
return rate;
clk->rate = clk->parent->rate;
rate = clk->parent->rate;
/* Otherwise, the parent must be a PLL */
if (WARN_ON(!clk->parent->pll_data))
return;
return rate;
pll = clk->parent->pll_data;
/* If pre-PLL, source clock is before the multiplier and divider(s) */
if (clk->flags & PRE_PLL)
clk->rate = pll->input_rate;
rate = pll->input_rate;
if (!clk->div_reg)
return;
return rate;
v = __raw_readl(pll->base + clk->div_reg);
if (v & PLLDIV_EN) {
plldiv = (v & PLLDIV_RATIO_MASK) + 1;
if (plldiv)
clk->rate /= plldiv;
rate /= plldiv;
}
return rate;
}
static void __init clk_pll_init(struct clk *clk)
static unsigned long clk_leafclk_recalc(struct clk *clk)
{
if (WARN_ON(!clk->parent))
return clk->rate;
return clk->parent->rate;
}
static unsigned long clk_pllclk_recalc(struct clk *clk)
{
u32 ctrl, mult = 1, prediv = 1, postdiv = 1;
u8 bypass;
struct pll_data *pll = clk->pll_data;
unsigned long rate = clk->rate;
pll->base = IO_ADDRESS(pll->phys_base);
ctrl = __raw_readl(pll->base + PLLCTL);
clk->rate = pll->input_rate = clk->parent->rate;
rate = pll->input_rate = clk->parent->rate;
if (ctrl & PLLCTL_PLLEN) {
bypass = 0;
@ -260,9 +276,9 @@ static void __init clk_pll_init(struct clk *clk)
}
if (!bypass) {
clk->rate /= prediv;
clk->rate *= mult;
clk->rate /= postdiv;
rate /= prediv;
rate *= mult;
rate /= postdiv;
}
pr_debug("PLL%d: input = %lu MHz [ ",
@ -275,7 +291,9 @@ static void __init clk_pll_init(struct clk *clk)
pr_debug("* %d ", mult);
if (postdiv > 1)
pr_debug("/ %d ", postdiv);
pr_debug("] --> %lu MHz output.\n", clk->rate / 1000000);
pr_debug("] --> %lu MHz output.\n", rate / 1000000);
return rate;
}
int __init davinci_clk_init(struct davinci_clk *clocks)
@ -286,12 +304,23 @@ int __init davinci_clk_init(struct davinci_clk *clocks)
for (c = clocks; c->lk.clk; c++) {
clk = c->lk.clk;
if (clk->pll_data)
clk_pll_init(clk);
if (!clk->recalc) {
/* Calculate rates for PLL-derived clocks */
else if (clk->flags & CLK_PLL)
clk_sysclk_recalc(clk);
/* Check if clock is a PLL */
if (clk->pll_data)
clk->recalc = clk_pllclk_recalc;
/* Else, if it is a PLL-derived clock */
else if (clk->flags & CLK_PLL)
clk->recalc = clk_sysclk_recalc;
/* Otherwise, it is a leaf clock (PSC clock) */
else if (clk->parent)
clk->recalc = clk_leafclk_recalc;
}
if (clk->recalc)
clk->rate = clk->recalc(clk);
if (clk->lpsc)
clk->flags |= CLK_PSC;

View file

@ -73,6 +73,7 @@ struct clk {
struct list_head childnode; /* parent's child list node */
struct pll_data *pll_data;
u32 div_reg;
unsigned long (*recalc) (struct clk *);
};
/* Clock flags */