diff options
| -rw-r--r-- | arch/arm/mach-ux500/clock.c | 51 | ||||
| -rw-r--r-- | arch/arm/mach-ux500/clock.h | 2 |
2 files changed, 53 insertions, 0 deletions
diff --git a/arch/arm/mach-ux500/clock.c b/arch/arm/mach-ux500/clock.c index 108014ea55b..13aaaf7e388 100644 --- a/arch/arm/mach-ux500/clock.c +++ b/arch/arm/mach-ux500/clock.c @@ -213,6 +213,36 @@ long clk_round_rate_rec(struct clk *clk, unsigned long rate) return rounded_rate; } +static void lock_parent_rate(struct clk *clk) +{ + unsigned long flags; + + if (clk->parent == NULL) + return; + + __clk_lock(clk->parent, clk->mutex, &flags); + + lock_parent_rate(clk->parent); + clk->parent->rate_locked++; + + __clk_unlock(clk->parent, clk->mutex, flags); +} + +static void unlock_parent_rate(struct clk *clk) +{ + unsigned long flags; + + if (clk->parent == NULL) + return; + + __clk_lock(clk->parent, clk->mutex, &flags); + + unlock_parent_rate(clk->parent); + clk->parent->rate_locked--; + + __clk_unlock(clk->parent, clk->mutex, flags); +} + int clk_set_rate(struct clk *clk, unsigned long rate) { int err; @@ -223,8 +253,20 @@ int clk_set_rate(struct clk *clk, unsigned long rate) __clk_lock(clk, NO_LOCK, &flags); + if (clk->enabled) { + err = -EBUSY; + goto unlock_and_return; + } + if (clk->rate_locked) { + err = -EAGAIN; + goto unlock_and_return; + } + + lock_parent_rate(clk); err = __clk_set_rate(clk, rate); + unlock_parent_rate(clk); +unlock_and_return: __clk_unlock(clk, NO_LOCK, flags); return err; @@ -241,8 +283,17 @@ int clk_set_rate_rec(struct clk *clk, unsigned long rate) __clk_lock(clk->parent, clk->mutex, &flags); + if (clk->parent->enabled) { + err = -EBUSY; + goto unlock_and_return; + } + if (clk->parent->rate_locked != 1) { + err = -EAGAIN; + goto unlock_and_return; + } err = __clk_set_rate(clk->parent, rate); +unlock_and_return: __clk_unlock(clk->parent, clk->mutex, flags); return err; diff --git a/arch/arm/mach-ux500/clock.h b/arch/arm/mach-ux500/clock.h index 39d8a61d79b..8bca502d968 100644 --- a/arch/arm/mach-ux500/clock.h +++ b/arch/arm/mach-ux500/clock.h @@ -18,6 +18,7 @@ * @mutex: The mutex to lock when operating on the clock. %NULL means that * the common clock spinlock will be used. * @enabled: A reference counter of the enable requests for the clock. + * @rate_locked: A rate lock counter used by clk_set_rate(). * @opp100: A flag saying whether the clock is requested to run at the * OPP 100%% frequency. * @rate: The frequency of the clock. For scalable and scaling clocks, @@ -39,6 +40,7 @@ struct clk { const char *name; struct mutex *mutex; unsigned int enabled; + unsigned int rate_locked; bool opp100; unsigned long rate; unsigned int io_base; |
