|
@@ -19,7 +19,6 @@
|
|
#include <linux/module.h>
|
|
#include <linux/module.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/list.h>
|
|
#include <linux/list.h>
|
|
-#include <linux/kref.h>
|
|
|
|
#include <linux/kobject.h>
|
|
#include <linux/kobject.h>
|
|
#include <linux/sysdev.h>
|
|
#include <linux/sysdev.h>
|
|
#include <linux/seq_file.h>
|
|
#include <linux/seq_file.h>
|
|
@@ -90,7 +89,7 @@ static void propagate_rate(struct clk *clk)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-static int __clk_enable(struct clk *clk)
|
|
|
|
|
|
+static void __clk_init(struct clk *clk)
|
|
{
|
|
{
|
|
/*
|
|
/*
|
|
* See if this is the first time we're enabling the clock, some
|
|
* See if this is the first time we're enabling the clock, some
|
|
@@ -100,19 +99,33 @@ static int __clk_enable(struct clk *clk)
|
|
* divisors to use before it can effectively recalc.
|
|
* divisors to use before it can effectively recalc.
|
|
*/
|
|
*/
|
|
|
|
|
|
- if (clk->flags & CLK_ALWAYS_ENABLED) {
|
|
|
|
- kref_get(&clk->kref);
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (unlikely(atomic_read(&clk->kref.refcount) == 1))
|
|
|
|
|
|
+ if (clk->flags & CLK_NEEDS_INIT) {
|
|
if (clk->ops && clk->ops->init)
|
|
if (clk->ops && clk->ops->init)
|
|
clk->ops->init(clk);
|
|
clk->ops->init(clk);
|
|
|
|
|
|
- kref_get(&clk->kref);
|
|
|
|
|
|
+ clk->flags &= ~CLK_NEEDS_INIT;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int __clk_enable(struct clk *clk)
|
|
|
|
+{
|
|
|
|
+ if (!clk)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ clk->usecount++;
|
|
|
|
+
|
|
|
|
+ /* nothing to do if always enabled */
|
|
|
|
+ if (clk->flags & CLK_ALWAYS_ENABLED)
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ if (clk->usecount == 1) {
|
|
|
|
+ __clk_init(clk);
|
|
|
|
|
|
- if (likely(clk->ops && clk->ops->enable))
|
|
|
|
- clk->ops->enable(clk);
|
|
|
|
|
|
+ __clk_enable(clk->parent);
|
|
|
|
+
|
|
|
|
+ if (clk->ops && clk->ops->enable)
|
|
|
|
+ clk->ops->enable(clk);
|
|
|
|
+ }
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -122,11 +135,6 @@ int clk_enable(struct clk *clk)
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
- if (!clk)
|
|
|
|
- return -EINVAL;
|
|
|
|
-
|
|
|
|
- clk_enable(clk->parent);
|
|
|
|
-
|
|
|
|
spin_lock_irqsave(&clock_lock, flags);
|
|
spin_lock_irqsave(&clock_lock, flags);
|
|
ret = __clk_enable(clk);
|
|
ret = __clk_enable(clk);
|
|
spin_unlock_irqrestore(&clock_lock, flags);
|
|
spin_unlock_irqrestore(&clock_lock, flags);
|
|
@@ -135,21 +143,23 @@ int clk_enable(struct clk *clk)
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(clk_enable);
|
|
EXPORT_SYMBOL_GPL(clk_enable);
|
|
|
|
|
|
-static void clk_kref_release(struct kref *kref)
|
|
|
|
-{
|
|
|
|
- /* Nothing to do */
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static void __clk_disable(struct clk *clk)
|
|
static void __clk_disable(struct clk *clk)
|
|
{
|
|
{
|
|
- int count = kref_put(&clk->kref, clk_kref_release);
|
|
|
|
|
|
+ if (!clk)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ clk->usecount--;
|
|
|
|
+
|
|
|
|
+ WARN_ON(clk->usecount < 0);
|
|
|
|
|
|
if (clk->flags & CLK_ALWAYS_ENABLED)
|
|
if (clk->flags & CLK_ALWAYS_ENABLED)
|
|
return;
|
|
return;
|
|
|
|
|
|
- if (!count) { /* count reaches zero, disable the clock */
|
|
|
|
|
|
+ if (clk->usecount == 0) {
|
|
if (likely(clk->ops && clk->ops->disable))
|
|
if (likely(clk->ops && clk->ops->disable))
|
|
clk->ops->disable(clk);
|
|
clk->ops->disable(clk);
|
|
|
|
+
|
|
|
|
+ __clk_disable(clk->parent);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -157,14 +167,9 @@ void clk_disable(struct clk *clk)
|
|
{
|
|
{
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
|
|
|
|
- if (!clk)
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
spin_lock_irqsave(&clock_lock, flags);
|
|
spin_lock_irqsave(&clock_lock, flags);
|
|
__clk_disable(clk);
|
|
__clk_disable(clk);
|
|
spin_unlock_irqrestore(&clock_lock, flags);
|
|
spin_unlock_irqrestore(&clock_lock, flags);
|
|
-
|
|
|
|
- clk_disable(clk->parent);
|
|
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(clk_disable);
|
|
EXPORT_SYMBOL_GPL(clk_disable);
|
|
|
|
|
|
@@ -173,14 +178,14 @@ int clk_register(struct clk *clk)
|
|
mutex_lock(&clock_list_sem);
|
|
mutex_lock(&clock_list_sem);
|
|
|
|
|
|
list_add(&clk->node, &clock_list);
|
|
list_add(&clk->node, &clock_list);
|
|
- kref_init(&clk->kref);
|
|
|
|
|
|
+ clk->usecount = 0;
|
|
|
|
+ clk->flags |= CLK_NEEDS_INIT;
|
|
|
|
|
|
mutex_unlock(&clock_list_sem);
|
|
mutex_unlock(&clock_list_sem);
|
|
|
|
|
|
if (clk->flags & CLK_ALWAYS_ENABLED) {
|
|
if (clk->flags & CLK_ALWAYS_ENABLED) {
|
|
|
|
+ __clk_init(clk);
|
|
pr_debug( "Clock '%s' is ALWAYS_ENABLED\n", clk->name);
|
|
pr_debug( "Clock '%s' is ALWAYS_ENABLED\n", clk->name);
|
|
- if (clk->ops && clk->ops->init)
|
|
|
|
- clk->ops->init(clk);
|
|
|
|
if (clk->ops && clk->ops->enable)
|
|
if (clk->ops && clk->ops->enable)
|
|
clk->ops->enable(clk);
|
|
clk->ops->enable(clk);
|
|
pr_debug( "Enabled.");
|
|
pr_debug( "Enabled.");
|
|
@@ -356,7 +361,7 @@ static int show_clocks(char *buf, char **start, off_t off,
|
|
p += sprintf(p, "%-12s\t: %ld.%02ldMHz\t%s\n", clk->name,
|
|
p += sprintf(p, "%-12s\t: %ld.%02ldMHz\t%s\n", clk->name,
|
|
rate / 1000000, (rate % 1000000) / 10000,
|
|
rate / 1000000, (rate % 1000000) / 10000,
|
|
((clk->flags & CLK_ALWAYS_ENABLED) ||
|
|
((clk->flags & CLK_ALWAYS_ENABLED) ||
|
|
- (atomic_read(&clk->kref.refcount) != 1)) ?
|
|
|
|
|
|
+ clk->usecount > 0) ?
|
|
"enabled" : "disabled");
|
|
"enabled" : "disabled");
|
|
}
|
|
}
|
|
|
|
|