diff options
Diffstat (limited to 'arch/arm/mach-davinci/clock.c')
| -rw-r--r-- | arch/arm/mach-davinci/clock.c | 120 |
1 files changed, 96 insertions, 24 deletions
diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c index 01ba080433d..985e5fd00fb 100644 --- a/arch/arm/mach-davinci/clock.c +++ b/arch/arm/mach-davinci/clock.c @@ -31,35 +31,68 @@ static LIST_HEAD(clocks); static DEFINE_MUTEX(clocks_mutex); static DEFINE_SPINLOCK(clockfw_lock); -static unsigned psc_domain(struct clk *clk) -{ - return (clk->flags & PSC_DSP) - ? DAVINCI_GPSC_DSPDOMAIN - : DAVINCI_GPSC_ARMDOMAIN; -} - static void __clk_enable(struct clk *clk) { if (clk->parent) __clk_enable(clk->parent); - if (clk->usecount++ == 0 && (clk->flags & CLK_PSC)) - davinci_psc_config(psc_domain(clk), clk->gpsc, clk->lpsc, - PSC_STATE_ENABLE); + if (clk->usecount++ == 0) { + if (clk->flags & CLK_PSC) + davinci_psc_config(clk->domain, clk->gpsc, clk->lpsc, + true, clk->flags); + else if (clk->clk_enable) + clk->clk_enable(clk); + } } static void __clk_disable(struct clk *clk) { if (WARN_ON(clk->usecount == 0)) return; - if (--clk->usecount == 0 && !(clk->flags & CLK_PLL) && - (clk->flags & CLK_PSC)) - davinci_psc_config(psc_domain(clk), clk->gpsc, clk->lpsc, - (clk->flags & PSC_SWRSTDISABLE) ? - PSC_STATE_SWRSTDISABLE : PSC_STATE_DISABLE); + if (--clk->usecount == 0) { + if (!(clk->flags & CLK_PLL) && (clk->flags & CLK_PSC)) + davinci_psc_config(clk->domain, clk->gpsc, clk->lpsc, + false, clk->flags); + else if (clk->clk_disable) + clk->clk_disable(clk); + } if (clk->parent) __clk_disable(clk->parent); } +int davinci_clk_reset(struct clk *clk, bool reset) +{ + unsigned long flags; + + if (clk == NULL || IS_ERR(clk)) + return -EINVAL; + + spin_lock_irqsave(&clockfw_lock, flags); + if (clk->flags & CLK_PSC) + davinci_psc_reset(clk->gpsc, clk->lpsc, reset); + spin_unlock_irqrestore(&clockfw_lock, flags); + + return 0; +} +EXPORT_SYMBOL(davinci_clk_reset); + +int davinci_clk_reset_assert(struct clk *clk) +{ + if (clk == NULL || IS_ERR(clk) || !clk->reset) + return -EINVAL; + + return clk->reset(clk, true); +} +EXPORT_SYMBOL(davinci_clk_reset_assert); + +int davinci_clk_reset_deassert(struct clk *clk) +{ + if (clk == NULL || IS_ERR(clk) || !clk->reset) + return -EINVAL; + + return clk->reset(clk, false); +} +EXPORT_SYMBOL(davinci_clk_reset_deassert); + int clk_enable(struct clk *clk) { unsigned long flags; @@ -100,7 +133,7 @@ EXPORT_SYMBOL(clk_get_rate); long clk_round_rate(struct clk *clk, unsigned long rate) { if (clk == NULL || IS_ERR(clk)) - return -EINVAL; + return 0; if (clk->round_rate) return clk->round_rate(clk, rate); @@ -221,7 +254,7 @@ EXPORT_SYMBOL(clk_unregister); /* * Disable any unused clocks left on by the bootloader */ -static int __init clk_disable_unused(void) +int __init davinci_clk_disable_unused(void) { struct clk *ck; @@ -238,15 +271,13 @@ static int __init clk_disable_unused(void) pr_debug("Clocks: disable unused %s\n", ck->name); - davinci_psc_config(psc_domain(ck), ck->gpsc, ck->lpsc, - (ck->flags & PSC_SWRSTDISABLE) ? - PSC_STATE_SWRSTDISABLE : PSC_STATE_DISABLE); + davinci_psc_config(ck->domain, ck->gpsc, ck->lpsc, + false, ck->flags); } spin_unlock_irq(&clockfw_lock); return 0; } -late_initcall(clk_disable_unused); #endif static unsigned long clk_sysclk_recalc(struct clk *clk) @@ -336,7 +367,7 @@ int davinci_set_sysclk_rate(struct clk *clk, unsigned long rate) ratio--; } - if (ratio > PLLDIV_RATIO_MASK) + if (ratio > pll->div_ratio_mask) return -EINVAL; do { @@ -344,7 +375,7 @@ int davinci_set_sysclk_rate(struct clk *clk, unsigned long rate) } while (v & PLLSTAT_GOSTAT); v = __raw_readl(pll->base + clk->div_reg); - v &= ~PLLDIV_RATIO_MASK; + v &= ~pll->div_ratio_mask; v |= ratio | PLLDIV_EN; __raw_writel(v, pll->base + clk->div_reg); @@ -368,6 +399,12 @@ static unsigned long clk_leafclk_recalc(struct clk *clk) return clk->parent->rate; } +int davinci_simple_set_rate(struct clk *clk, unsigned long rate) +{ + clk->rate = rate; + return 0; +} + static unsigned long clk_pllclk_recalc(struct clk *clk) { u32 ctrl, mult = 1, prediv = 1, postdiv = 1; @@ -506,8 +543,40 @@ int davinci_set_pllrate(struct pll_data *pll, unsigned int prediv, } EXPORT_SYMBOL(davinci_set_pllrate); +/** + * davinci_set_refclk_rate() - Set the reference clock rate + * @rate: The new rate. + * + * Sets the reference clock rate to a given value. This will most likely + * result in the entire clock tree getting updated. + * + * This is used to support boards which use a reference clock different + * than that used by default in <soc>.c file. The reference clock rate + * should be updated early in the boot process; ideally soon after the + * clock tree has been initialized once with the default reference clock + * rate (davinci_common_init()). + * + * Returns 0 on success, error otherwise. + */ +int davinci_set_refclk_rate(unsigned long rate) +{ + struct clk *refclk; + + refclk = clk_get(NULL, "ref"); + if (IS_ERR(refclk)) { + pr_err("%s: failed to get reference clock.\n", __func__); + return PTR_ERR(refclk); + } + + clk_set_rate(refclk, rate); + + clk_put(refclk); + + return 0; +} + int __init davinci_clk_init(struct clk_lookup *clocks) - { +{ struct clk_lookup *c; struct clk *clk; size_t num_clocks = 0; @@ -548,6 +617,9 @@ int __init davinci_clk_init(struct clk_lookup *clocks) if (clk->lpsc) clk->flags |= CLK_PSC; + if (clk->flags & PSC_LRST) + clk->reset = davinci_clk_reset; + clk_register(clk); num_clocks++; |
