Skip to content

Commit

Permalink
davinci: make clock rate re-calculation easy
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Sekhar Nori authored and Kevin Hilman committed Nov 25, 2009
1 parent f02bf3b commit de381a9
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 20 deletions.
69 changes: 49 additions & 20 deletions arch/arm/mach-davinci/clock.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 unsigned long clk_leafclk_recalc(struct clk *clk)
{
if (WARN_ON(!clk->parent))
return clk->rate;

return clk->parent->rate;
}

static void __init clk_pll_init(struct clk *clk)
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;
Expand Down Expand Up @@ -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 [ ",
Expand All @@ -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)
Expand All @@ -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) {

/* 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;
}

/* Calculate rates for PLL-derived clocks */
else if (clk->flags & CLK_PLL)
clk_sysclk_recalc(clk);
if (clk->recalc)
clk->rate = clk->recalc(clk);

if (clk->lpsc)
clk->flags |= CLK_PSC;
Expand Down
1 change: 1 addition & 0 deletions arch/arm/mach-davinci/clock.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down

0 comments on commit de381a9

Please sign in to comment.