summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
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;