From 1aa49d2ca8c5bdf6c99c7f0f78796b07f7cf39c0 Mon Sep 17 00:00:00 2001 From: Mattias Nilsson Date: Tue, 4 Oct 2011 12:39:05 +0200 Subject: arm: ux500: updated clk_set_rate This patch updates clk_set_rate so that it only works for disabled clocks, as well as making sure that it doesn't interfere with itself at another depth of the clock tree. ST Ericsson ID: 343004, 359227 ST Ericsson FOSS-OUT ID: trivial Change-Id: I9dbf32f73e89f8f248e51b15097b50975b951a73 Signed-off-by: Mattias Nilsson Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/32967 Reviewed-by: Jonas ABERG --- arch/arm/mach-ux500/clock.c | 51 +++++++++++++++++++++++++++++++++++++++++++++ arch/arm/mach-ux500/clock.h | 2 ++ 2 files changed, 53 insertions(+) (limited to 'arch') 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; -- cgit v1.2.3