summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorMattias Nilsson <mattias.i.nilsson@stericsson.com>2011-10-04 12:39:05 +0200
committerJonas ABERG <jonas.aberg@stericsson.com>2011-10-19 17:07:49 +0200
commit1aa49d2ca8c5bdf6c99c7f0f78796b07f7cf39c0 (patch)
treea42599b1d156187dbc70daf62f8583e6091e8caa /arch
parent73c1b95de017a4cf01127ccadad2ed88007bcb52 (diff)
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 <mattias.i.nilsson@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/32967 Reviewed-by: Jonas ABERG <jonas.aberg@stericsson.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-ux500/clock.c51
-rw-r--r--arch/arm/mach-ux500/clock.h2
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;