aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/sh/clk.c91
-rw-r--r--include/linux/sh_clk.h10
2 files changed, 99 insertions, 2 deletions
diff --git a/drivers/sh/clk.c b/drivers/sh/clk.c
index 661a801126ad..813d97cdad49 100644
--- a/drivers/sh/clk.c
+++ b/drivers/sh/clk.c
@@ -25,7 +25,7 @@
25#include <linux/sysdev.h> 25#include <linux/sysdev.h>
26#include <linux/seq_file.h> 26#include <linux/seq_file.h>
27#include <linux/err.h> 27#include <linux/err.h>
28#include <linux/platform_device.h> 28#include <linux/io.h>
29#include <linux/debugfs.h> 29#include <linux/debugfs.h>
30#include <linux/cpufreq.h> 30#include <linux/cpufreq.h>
31#include <linux/clk.h> 31#include <linux/clk.h>
@@ -251,8 +251,88 @@ void recalculate_root_clocks(void)
251 } 251 }
252} 252}
253 253
254static struct clk_mapping dummy_mapping;
255
256static struct clk *lookup_root_clock(struct clk *clk)
257{
258 while (clk->parent)
259 clk = clk->parent;
260
261 return clk;
262}
263
264static int clk_establish_mapping(struct clk *clk)
265{
266 struct clk_mapping *mapping = clk->mapping;
267
268 /*
269 * Propagate mappings.
270 */
271 if (!mapping) {
272 struct clk *clkp;
273
274 /*
275 * dummy mapping for root clocks with no specified ranges
276 */
277 if (!clk->parent) {
278 clk->mapping = &dummy_mapping;
279 return 0;
280 }
281
282 /*
283 * If we're on a child clock and it provides no mapping of its
284 * own, inherit the mapping from its root clock.
285 */
286 clkp = lookup_root_clock(clk);
287 mapping = clkp->mapping;
288 BUG_ON(!mapping);
289 }
290
291 /*
292 * Establish initial mapping.
293 */
294 if (!mapping->base && mapping->phys) {
295 kref_init(&mapping->ref);
296
297 mapping->base = ioremap_nocache(mapping->phys, mapping->len);
298 if (unlikely(!mapping->base))
299 return -ENXIO;
300 } else if (mapping->base) {
301 /*
302 * Bump the refcount for an existing mapping
303 */
304 kref_get(&mapping->ref);
305 }
306
307 clk->mapping = mapping;
308 return 0;
309}
310
311static void clk_destroy_mapping(struct kref *kref)
312{
313 struct clk_mapping *mapping;
314
315 mapping = container_of(kref, struct clk_mapping, ref);
316
317 iounmap(mapping->base);
318}
319
320static void clk_teardown_mapping(struct clk *clk)
321{
322 struct clk_mapping *mapping = clk->mapping;
323
324 /* Nothing to do */
325 if (mapping == &dummy_mapping)
326 return;
327
328 kref_put(&mapping->ref, clk_destroy_mapping);
329 clk->mapping = NULL;
330}
331
254int clk_register(struct clk *clk) 332int clk_register(struct clk *clk)
255{ 333{
334 int ret;
335
256 if (clk == NULL || IS_ERR(clk)) 336 if (clk == NULL || IS_ERR(clk))
257 return -EINVAL; 337 return -EINVAL;
258 338
@@ -267,6 +347,10 @@ int clk_register(struct clk *clk)
267 INIT_LIST_HEAD(&clk->children); 347 INIT_LIST_HEAD(&clk->children);
268 clk->usecount = 0; 348 clk->usecount = 0;
269 349
350 ret = clk_establish_mapping(clk);
351 if (unlikely(ret))
352 goto out_unlock;
353
270 if (clk->parent) 354 if (clk->parent)
271 list_add(&clk->sibling, &clk->parent->children); 355 list_add(&clk->sibling, &clk->parent->children);
272 else 356 else
@@ -275,9 +359,11 @@ int clk_register(struct clk *clk)
275 list_add(&clk->node, &clock_list); 359 list_add(&clk->node, &clock_list);
276 if (clk->ops && clk->ops->init) 360 if (clk->ops && clk->ops->init)
277 clk->ops->init(clk); 361 clk->ops->init(clk);
362
363out_unlock:
278 mutex_unlock(&clock_list_sem); 364 mutex_unlock(&clock_list_sem);
279 365
280 return 0; 366 return ret;
281} 367}
282EXPORT_SYMBOL_GPL(clk_register); 368EXPORT_SYMBOL_GPL(clk_register);
283 369
@@ -286,6 +372,7 @@ void clk_unregister(struct clk *clk)
286 mutex_lock(&clock_list_sem); 372 mutex_lock(&clock_list_sem);
287 list_del(&clk->sibling); 373 list_del(&clk->sibling);
288 list_del(&clk->node); 374 list_del(&clk->node);
375 clk_teardown_mapping(clk);
289 mutex_unlock(&clock_list_sem); 376 mutex_unlock(&clock_list_sem);
290} 377}
291EXPORT_SYMBOL_GPL(clk_unregister); 378EXPORT_SYMBOL_GPL(clk_unregister);
diff --git a/include/linux/sh_clk.h b/include/linux/sh_clk.h
index ecdfea54a49e..8ae37707a4a4 100644
--- a/include/linux/sh_clk.h
+++ b/include/linux/sh_clk.h
@@ -4,11 +4,20 @@
4#include <linux/list.h> 4#include <linux/list.h>
5#include <linux/seq_file.h> 5#include <linux/seq_file.h>
6#include <linux/cpufreq.h> 6#include <linux/cpufreq.h>
7#include <linux/types.h>
8#include <linux/kref.h>
7#include <linux/clk.h> 9#include <linux/clk.h>
8#include <linux/err.h> 10#include <linux/err.h>
9 11
10struct clk; 12struct clk;
11 13
14struct clk_mapping {
15 phys_addr_t phys;
16 void __iomem *base;
17 unsigned long len;
18 struct kref ref;
19};
20
12struct clk_ops { 21struct clk_ops {
13 void (*init)(struct clk *clk); 22 void (*init)(struct clk *clk);
14 int (*enable)(struct clk *clk); 23 int (*enable)(struct clk *clk);
@@ -42,6 +51,7 @@ struct clk {
42 unsigned long arch_flags; 51 unsigned long arch_flags;
43 void *priv; 52 void *priv;
44 struct dentry *dentry; 53 struct dentry *dentry;
54 struct clk_mapping *mapping;
45 struct cpufreq_frequency_table *freq_table; 55 struct cpufreq_frequency_table *freq_table;
46}; 56};
47 57