diff options
| -rw-r--r-- | drivers/sh/clk.c | 91 | ||||
| -rw-r--r-- | include/linux/sh_clk.h | 10 |
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 | ||
| 254 | static struct clk_mapping dummy_mapping; | ||
| 255 | |||
| 256 | static struct clk *lookup_root_clock(struct clk *clk) | ||
| 257 | { | ||
| 258 | while (clk->parent) | ||
| 259 | clk = clk->parent; | ||
| 260 | |||
| 261 | return clk; | ||
| 262 | } | ||
| 263 | |||
| 264 | static 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 | |||
| 311 | static 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 | |||
| 320 | static 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 | |||
| 254 | int clk_register(struct clk *clk) | 332 | int 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 | |||
| 363 | out_unlock: | ||
| 278 | mutex_unlock(&clock_list_sem); | 364 | mutex_unlock(&clock_list_sem); |
| 279 | 365 | ||
| 280 | return 0; | 366 | return ret; |
| 281 | } | 367 | } |
| 282 | EXPORT_SYMBOL_GPL(clk_register); | 368 | EXPORT_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 | } |
| 291 | EXPORT_SYMBOL_GPL(clk_unregister); | 378 | EXPORT_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 | ||
| 10 | struct clk; | 12 | struct clk; |
| 11 | 13 | ||
| 14 | struct clk_mapping { | ||
| 15 | phys_addr_t phys; | ||
| 16 | void __iomem *base; | ||
| 17 | unsigned long len; | ||
| 18 | struct kref ref; | ||
| 19 | }; | ||
| 20 | |||
| 12 | struct clk_ops { | 21 | struct 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 | ||
