diff options
Diffstat (limited to 'arch/arm/plat-omap/clock.c')
| -rw-r--r-- | arch/arm/plat-omap/clock.c | 198 |
1 files changed, 76 insertions, 122 deletions
diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c index be6aab9c6834..2e0614552ac8 100644 --- a/arch/arm/plat-omap/clock.c +++ b/arch/arm/plat-omap/clock.c | |||
| @@ -36,44 +36,6 @@ static struct clk_functions *arch_clock; | |||
| 36 | * Standard clock functions defined in include/linux/clk.h | 36 | * Standard clock functions defined in include/linux/clk.h |
| 37 | *-------------------------------------------------------------------------*/ | 37 | *-------------------------------------------------------------------------*/ |
| 38 | 38 | ||
| 39 | /* | ||
| 40 | * Returns a clock. Note that we first try to use device id on the bus | ||
| 41 | * and clock name. If this fails, we try to use clock name only. | ||
| 42 | */ | ||
| 43 | struct clk * clk_get(struct device *dev, const char *id) | ||
| 44 | { | ||
| 45 | struct clk *p, *clk = ERR_PTR(-ENOENT); | ||
| 46 | int idno; | ||
| 47 | |||
| 48 | if (dev == NULL || dev->bus != &platform_bus_type) | ||
| 49 | idno = -1; | ||
| 50 | else | ||
| 51 | idno = to_platform_device(dev)->id; | ||
| 52 | |||
| 53 | mutex_lock(&clocks_mutex); | ||
| 54 | |||
| 55 | list_for_each_entry(p, &clocks, node) { | ||
| 56 | if (p->id == idno && | ||
| 57 | strcmp(id, p->name) == 0 && try_module_get(p->owner)) { | ||
| 58 | clk = p; | ||
| 59 | goto found; | ||
| 60 | } | ||
| 61 | } | ||
| 62 | |||
| 63 | list_for_each_entry(p, &clocks, node) { | ||
| 64 | if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) { | ||
| 65 | clk = p; | ||
| 66 | break; | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | found: | ||
| 71 | mutex_unlock(&clocks_mutex); | ||
| 72 | |||
| 73 | return clk; | ||
| 74 | } | ||
| 75 | EXPORT_SYMBOL(clk_get); | ||
| 76 | |||
| 77 | int clk_enable(struct clk *clk) | 39 | int clk_enable(struct clk *clk) |
| 78 | { | 40 | { |
| 79 | unsigned long flags; | 41 | unsigned long flags; |
| @@ -114,22 +76,6 @@ out: | |||
| 114 | } | 76 | } |
| 115 | EXPORT_SYMBOL(clk_disable); | 77 | EXPORT_SYMBOL(clk_disable); |
| 116 | 78 | ||
| 117 | int clk_get_usecount(struct clk *clk) | ||
| 118 | { | ||
| 119 | unsigned long flags; | ||
| 120 | int ret = 0; | ||
| 121 | |||
| 122 | if (clk == NULL || IS_ERR(clk)) | ||
| 123 | return 0; | ||
| 124 | |||
| 125 | spin_lock_irqsave(&clockfw_lock, flags); | ||
| 126 | ret = clk->usecount; | ||
| 127 | spin_unlock_irqrestore(&clockfw_lock, flags); | ||
| 128 | |||
| 129 | return ret; | ||
| 130 | } | ||
| 131 | EXPORT_SYMBOL(clk_get_usecount); | ||
| 132 | |||
| 133 | unsigned long clk_get_rate(struct clk *clk) | 79 | unsigned long clk_get_rate(struct clk *clk) |
| 134 | { | 80 | { |
| 135 | unsigned long flags; | 81 | unsigned long flags; |
| @@ -146,13 +92,6 @@ unsigned long clk_get_rate(struct clk *clk) | |||
| 146 | } | 92 | } |
| 147 | EXPORT_SYMBOL(clk_get_rate); | 93 | EXPORT_SYMBOL(clk_get_rate); |
| 148 | 94 | ||
| 149 | void clk_put(struct clk *clk) | ||
| 150 | { | ||
| 151 | if (clk && !IS_ERR(clk)) | ||
| 152 | module_put(clk->owner); | ||
| 153 | } | ||
| 154 | EXPORT_SYMBOL(clk_put); | ||
| 155 | |||
| 156 | /*------------------------------------------------------------------------- | 95 | /*------------------------------------------------------------------------- |
| 157 | * Optional clock functions defined in include/linux/clk.h | 96 | * Optional clock functions defined in include/linux/clk.h |
| 158 | *-------------------------------------------------------------------------*/ | 97 | *-------------------------------------------------------------------------*/ |
| @@ -185,6 +124,11 @@ int clk_set_rate(struct clk *clk, unsigned long rate) | |||
| 185 | spin_lock_irqsave(&clockfw_lock, flags); | 124 | spin_lock_irqsave(&clockfw_lock, flags); |
| 186 | if (arch_clock->clk_set_rate) | 125 | if (arch_clock->clk_set_rate) |
| 187 | ret = arch_clock->clk_set_rate(clk, rate); | 126 | ret = arch_clock->clk_set_rate(clk, rate); |
| 127 | if (ret == 0) { | ||
| 128 | if (clk->recalc) | ||
| 129 | clk->rate = clk->recalc(clk); | ||
| 130 | propagate_rate(clk); | ||
| 131 | } | ||
| 188 | spin_unlock_irqrestore(&clockfw_lock, flags); | 132 | spin_unlock_irqrestore(&clockfw_lock, flags); |
| 189 | 133 | ||
| 190 | return ret; | 134 | return ret; |
| @@ -200,8 +144,16 @@ int clk_set_parent(struct clk *clk, struct clk *parent) | |||
| 200 | return ret; | 144 | return ret; |
| 201 | 145 | ||
| 202 | spin_lock_irqsave(&clockfw_lock, flags); | 146 | spin_lock_irqsave(&clockfw_lock, flags); |
| 203 | if (arch_clock->clk_set_parent) | 147 | if (clk->usecount == 0) { |
| 204 | ret = arch_clock->clk_set_parent(clk, parent); | 148 | if (arch_clock->clk_set_parent) |
| 149 | ret = arch_clock->clk_set_parent(clk, parent); | ||
| 150 | if (ret == 0) { | ||
| 151 | if (clk->recalc) | ||
| 152 | clk->rate = clk->recalc(clk); | ||
| 153 | propagate_rate(clk); | ||
| 154 | } | ||
| 155 | } else | ||
| 156 | ret = -EBUSY; | ||
| 205 | spin_unlock_irqrestore(&clockfw_lock, flags); | 157 | spin_unlock_irqrestore(&clockfw_lock, flags); |
| 206 | 158 | ||
| 207 | return ret; | 159 | return ret; |
| @@ -210,18 +162,7 @@ EXPORT_SYMBOL(clk_set_parent); | |||
| 210 | 162 | ||
| 211 | struct clk *clk_get_parent(struct clk *clk) | 163 | struct clk *clk_get_parent(struct clk *clk) |
| 212 | { | 164 | { |
| 213 | unsigned long flags; | 165 | return clk->parent; |
| 214 | struct clk * ret = NULL; | ||
| 215 | |||
| 216 | if (clk == NULL || IS_ERR(clk)) | ||
| 217 | return ret; | ||
| 218 | |||
| 219 | spin_lock_irqsave(&clockfw_lock, flags); | ||
| 220 | if (arch_clock->clk_get_parent) | ||
| 221 | ret = arch_clock->clk_get_parent(clk); | ||
| 222 | spin_unlock_irqrestore(&clockfw_lock, flags); | ||
| 223 | |||
| 224 | return ret; | ||
| 225 | } | 166 | } |
| 226 | EXPORT_SYMBOL(clk_get_parent); | 167 | EXPORT_SYMBOL(clk_get_parent); |
| 227 | 168 | ||
| @@ -250,14 +191,20 @@ static int __init omap_clk_setup(char *str) | |||
| 250 | __setup("mpurate=", omap_clk_setup); | 191 | __setup("mpurate=", omap_clk_setup); |
| 251 | 192 | ||
| 252 | /* Used for clocks that always have same value as the parent clock */ | 193 | /* Used for clocks that always have same value as the parent clock */ |
| 253 | void followparent_recalc(struct clk *clk) | 194 | unsigned long followparent_recalc(struct clk *clk) |
| 254 | { | 195 | { |
| 255 | if (clk == NULL || IS_ERR(clk)) | 196 | return clk->parent->rate; |
| 256 | return; | 197 | } |
| 257 | 198 | ||
| 258 | clk->rate = clk->parent->rate; | 199 | void clk_reparent(struct clk *child, struct clk *parent) |
| 259 | if (unlikely(clk->flags & RATE_PROPAGATES)) | 200 | { |
| 260 | propagate_rate(clk); | 201 | list_del_init(&child->sibling); |
| 202 | if (parent) | ||
| 203 | list_add(&child->sibling, &parent->children); | ||
| 204 | child->parent = parent; | ||
| 205 | |||
| 206 | /* now do the debugfs renaming to reattach the child | ||
| 207 | to the proper parent */ | ||
| 261 | } | 208 | } |
| 262 | 209 | ||
| 263 | /* Propagate rate to children */ | 210 | /* Propagate rate to children */ |
| @@ -265,17 +212,15 @@ void propagate_rate(struct clk * tclk) | |||
| 265 | { | 212 | { |
| 266 | struct clk *clkp; | 213 | struct clk *clkp; |
| 267 | 214 | ||
| 268 | if (tclk == NULL || IS_ERR(tclk)) | 215 | list_for_each_entry(clkp, &tclk->children, sibling) { |
| 269 | return; | 216 | if (clkp->recalc) |
| 270 | 217 | clkp->rate = clkp->recalc(clkp); | |
| 271 | list_for_each_entry(clkp, &clocks, node) { | 218 | propagate_rate(clkp); |
| 272 | if (likely(clkp->parent != tclk)) | ||
| 273 | continue; | ||
| 274 | if (likely((u32)clkp->recalc)) | ||
| 275 | clkp->recalc(clkp); | ||
| 276 | } | 219 | } |
| 277 | } | 220 | } |
| 278 | 221 | ||
| 222 | static LIST_HEAD(root_clks); | ||
| 223 | |||
| 279 | /** | 224 | /** |
| 280 | * recalculate_root_clocks - recalculate and propagate all root clocks | 225 | * recalculate_root_clocks - recalculate and propagate all root clocks |
| 281 | * | 226 | * |
| @@ -287,18 +232,35 @@ void recalculate_root_clocks(void) | |||
| 287 | { | 232 | { |
| 288 | struct clk *clkp; | 233 | struct clk *clkp; |
| 289 | 234 | ||
| 290 | list_for_each_entry(clkp, &clocks, node) { | 235 | list_for_each_entry(clkp, &root_clks, sibling) { |
| 291 | if (unlikely(!clkp->parent) && likely((u32)clkp->recalc)) | 236 | if (clkp->recalc) |
| 292 | clkp->recalc(clkp); | 237 | clkp->rate = clkp->recalc(clkp); |
| 238 | propagate_rate(clkp); | ||
| 293 | } | 239 | } |
| 294 | } | 240 | } |
| 295 | 241 | ||
| 242 | void clk_init_one(struct clk *clk) | ||
| 243 | { | ||
| 244 | INIT_LIST_HEAD(&clk->children); | ||
| 245 | } | ||
| 246 | |||
| 296 | int clk_register(struct clk *clk) | 247 | int clk_register(struct clk *clk) |
| 297 | { | 248 | { |
| 298 | if (clk == NULL || IS_ERR(clk)) | 249 | if (clk == NULL || IS_ERR(clk)) |
| 299 | return -EINVAL; | 250 | return -EINVAL; |
| 300 | 251 | ||
| 252 | /* | ||
| 253 | * trap out already registered clocks | ||
| 254 | */ | ||
| 255 | if (clk->node.next || clk->node.prev) | ||
| 256 | return 0; | ||
| 257 | |||
| 301 | mutex_lock(&clocks_mutex); | 258 | mutex_lock(&clocks_mutex); |
| 259 | if (clk->parent) | ||
| 260 | list_add(&clk->sibling, &clk->parent->children); | ||
| 261 | else | ||
| 262 | list_add(&clk->sibling, &root_clks); | ||
| 263 | |||
| 302 | list_add(&clk->node, &clocks); | 264 | list_add(&clk->node, &clocks); |
| 303 | if (clk->init) | 265 | if (clk->init) |
| 304 | clk->init(clk); | 266 | clk->init(clk); |
| @@ -314,39 +276,12 @@ void clk_unregister(struct clk *clk) | |||
| 314 | return; | 276 | return; |
| 315 | 277 | ||
| 316 | mutex_lock(&clocks_mutex); | 278 | mutex_lock(&clocks_mutex); |
| 279 | list_del(&clk->sibling); | ||
| 317 | list_del(&clk->node); | 280 | list_del(&clk->node); |
| 318 | mutex_unlock(&clocks_mutex); | 281 | mutex_unlock(&clocks_mutex); |
| 319 | } | 282 | } |
| 320 | EXPORT_SYMBOL(clk_unregister); | 283 | EXPORT_SYMBOL(clk_unregister); |
| 321 | 284 | ||
| 322 | void clk_deny_idle(struct clk *clk) | ||
| 323 | { | ||
| 324 | unsigned long flags; | ||
| 325 | |||
| 326 | if (clk == NULL || IS_ERR(clk)) | ||
| 327 | return; | ||
| 328 | |||
| 329 | spin_lock_irqsave(&clockfw_lock, flags); | ||
| 330 | if (arch_clock->clk_deny_idle) | ||
| 331 | arch_clock->clk_deny_idle(clk); | ||
| 332 | spin_unlock_irqrestore(&clockfw_lock, flags); | ||
| 333 | } | ||
| 334 | EXPORT_SYMBOL(clk_deny_idle); | ||
| 335 | |||
| 336 | void clk_allow_idle(struct clk *clk) | ||
| 337 | { | ||
| 338 | unsigned long flags; | ||
| 339 | |||
| 340 | if (clk == NULL || IS_ERR(clk)) | ||
| 341 | return; | ||
| 342 | |||
| 343 | spin_lock_irqsave(&clockfw_lock, flags); | ||
| 344 | if (arch_clock->clk_allow_idle) | ||
| 345 | arch_clock->clk_allow_idle(clk); | ||
| 346 | spin_unlock_irqrestore(&clockfw_lock, flags); | ||
| 347 | } | ||
| 348 | EXPORT_SYMBOL(clk_allow_idle); | ||
| 349 | |||
| 350 | void clk_enable_init_clocks(void) | 285 | void clk_enable_init_clocks(void) |
| 351 | { | 286 | { |
| 352 | struct clk *clkp; | 287 | struct clk *clkp; |
| @@ -358,6 +293,23 @@ void clk_enable_init_clocks(void) | |||
| 358 | } | 293 | } |
| 359 | EXPORT_SYMBOL(clk_enable_init_clocks); | 294 | EXPORT_SYMBOL(clk_enable_init_clocks); |
| 360 | 295 | ||
| 296 | /* | ||
| 297 | * Low level helpers | ||
| 298 | */ | ||
| 299 | static int clkll_enable_null(struct clk *clk) | ||
| 300 | { | ||
| 301 | return 0; | ||
| 302 | } | ||
| 303 | |||
| 304 | static void clkll_disable_null(struct clk *clk) | ||
| 305 | { | ||
| 306 | } | ||
| 307 | |||
| 308 | const struct clkops clkops_null = { | ||
| 309 | .enable = clkll_enable_null, | ||
| 310 | .disable = clkll_disable_null, | ||
| 311 | }; | ||
| 312 | |||
| 361 | #ifdef CONFIG_CPU_FREQ | 313 | #ifdef CONFIG_CPU_FREQ |
| 362 | void clk_init_cpufreq_table(struct cpufreq_frequency_table **table) | 314 | void clk_init_cpufreq_table(struct cpufreq_frequency_table **table) |
| 363 | { | 315 | { |
| @@ -383,8 +335,10 @@ static int __init clk_disable_unused(void) | |||
| 383 | unsigned long flags; | 335 | unsigned long flags; |
| 384 | 336 | ||
| 385 | list_for_each_entry(ck, &clocks, node) { | 337 | list_for_each_entry(ck, &clocks, node) { |
| 386 | if (ck->usecount > 0 || (ck->flags & ALWAYS_ENABLED) || | 338 | if (ck->ops == &clkops_null) |
| 387 | ck->enable_reg == 0) | 339 | continue; |
| 340 | |||
| 341 | if (ck->usecount > 0 || ck->enable_reg == 0) | ||
| 388 | continue; | 342 | continue; |
| 389 | 343 | ||
| 390 | spin_lock_irqsave(&clockfw_lock, flags); | 344 | spin_lock_irqsave(&clockfw_lock, flags); |
