mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-30 08:02:30 +00:00
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:
parent
f02bf3b396
commit
de381a91f5
2 changed files with 50 additions and 20 deletions
|
@ -135,8 +135,12 @@ int clk_register(struct clk *clk)
|
||||||
if (clk->rate)
|
if (clk->rate)
|
||||||
return 0;
|
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 */
|
/* Otherwise, default to parent rate */
|
||||||
if (clk->parent)
|
else if (clk->parent)
|
||||||
clk->rate = clk->parent->rate;
|
clk->rate = clk->parent->rate;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -184,50 +188,62 @@ static int __init clk_disable_unused(void)
|
||||||
late_initcall(clk_disable_unused);
|
late_initcall(clk_disable_unused);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void clk_sysclk_recalc(struct clk *clk)
|
static unsigned long clk_sysclk_recalc(struct clk *clk)
|
||||||
{
|
{
|
||||||
u32 v, plldiv;
|
u32 v, plldiv;
|
||||||
struct pll_data *pll;
|
struct pll_data *pll;
|
||||||
|
unsigned long rate = clk->rate;
|
||||||
|
|
||||||
/* If this is the PLL base clock, no more calculations needed */
|
/* If this is the PLL base clock, no more calculations needed */
|
||||||
if (clk->pll_data)
|
if (clk->pll_data)
|
||||||
return;
|
return rate;
|
||||||
|
|
||||||
if (WARN_ON(!clk->parent))
|
if (WARN_ON(!clk->parent))
|
||||||
return;
|
return rate;
|
||||||
|
|
||||||
clk->rate = clk->parent->rate;
|
rate = clk->parent->rate;
|
||||||
|
|
||||||
/* Otherwise, the parent must be a PLL */
|
/* Otherwise, the parent must be a PLL */
|
||||||
if (WARN_ON(!clk->parent->pll_data))
|
if (WARN_ON(!clk->parent->pll_data))
|
||||||
return;
|
return rate;
|
||||||
|
|
||||||
pll = clk->parent->pll_data;
|
pll = clk->parent->pll_data;
|
||||||
|
|
||||||
/* If pre-PLL, source clock is before the multiplier and divider(s) */
|
/* If pre-PLL, source clock is before the multiplier and divider(s) */
|
||||||
if (clk->flags & PRE_PLL)
|
if (clk->flags & PRE_PLL)
|
||||||
clk->rate = pll->input_rate;
|
rate = pll->input_rate;
|
||||||
|
|
||||||
if (!clk->div_reg)
|
if (!clk->div_reg)
|
||||||
return;
|
return rate;
|
||||||
|
|
||||||
v = __raw_readl(pll->base + clk->div_reg);
|
v = __raw_readl(pll->base + clk->div_reg);
|
||||||
if (v & PLLDIV_EN) {
|
if (v & PLLDIV_EN) {
|
||||||
plldiv = (v & PLLDIV_RATIO_MASK) + 1;
|
plldiv = (v & PLLDIV_RATIO_MASK) + 1;
|
||||||
if (plldiv)
|
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;
|
u32 ctrl, mult = 1, prediv = 1, postdiv = 1;
|
||||||
u8 bypass;
|
u8 bypass;
|
||||||
struct pll_data *pll = clk->pll_data;
|
struct pll_data *pll = clk->pll_data;
|
||||||
|
unsigned long rate = clk->rate;
|
||||||
|
|
||||||
pll->base = IO_ADDRESS(pll->phys_base);
|
pll->base = IO_ADDRESS(pll->phys_base);
|
||||||
ctrl = __raw_readl(pll->base + PLLCTL);
|
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) {
|
if (ctrl & PLLCTL_PLLEN) {
|
||||||
bypass = 0;
|
bypass = 0;
|
||||||
|
@ -260,9 +276,9 @@ static void __init clk_pll_init(struct clk *clk)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bypass) {
|
if (!bypass) {
|
||||||
clk->rate /= prediv;
|
rate /= prediv;
|
||||||
clk->rate *= mult;
|
rate *= mult;
|
||||||
clk->rate /= postdiv;
|
rate /= postdiv;
|
||||||
}
|
}
|
||||||
|
|
||||||
pr_debug("PLL%d: input = %lu MHz [ ",
|
pr_debug("PLL%d: input = %lu MHz [ ",
|
||||||
|
@ -275,7 +291,9 @@ static void __init clk_pll_init(struct clk *clk)
|
||||||
pr_debug("* %d ", mult);
|
pr_debug("* %d ", mult);
|
||||||
if (postdiv > 1)
|
if (postdiv > 1)
|
||||||
pr_debug("/ %d ", postdiv);
|
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)
|
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++) {
|
for (c = clocks; c->lk.clk; c++) {
|
||||||
clk = c->lk.clk;
|
clk = c->lk.clk;
|
||||||
|
|
||||||
if (clk->pll_data)
|
if (!clk->recalc) {
|
||||||
clk_pll_init(clk);
|
|
||||||
|
|
||||||
/* Calculate rates for PLL-derived clocks */
|
/* Check if clock is a PLL */
|
||||||
else if (clk->flags & CLK_PLL)
|
if (clk->pll_data)
|
||||||
clk_sysclk_recalc(clk);
|
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)
|
if (clk->lpsc)
|
||||||
clk->flags |= CLK_PSC;
|
clk->flags |= CLK_PSC;
|
||||||
|
|
|
@ -73,6 +73,7 @@ struct clk {
|
||||||
struct list_head childnode; /* parent's child list node */
|
struct list_head childnode; /* parent's child list node */
|
||||||
struct pll_data *pll_data;
|
struct pll_data *pll_data;
|
||||||
u32 div_reg;
|
u32 div_reg;
|
||||||
|
unsigned long (*recalc) (struct clk *);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Clock flags */
|
/* Clock flags */
|
||||||
|
|
Loading…
Reference in a new issue