viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 1 | /* |
| 2 | * arch/arm/plat-spear/clock.c |
| 3 | * |
| 4 | * Clock framework for SPEAr platform |
| 5 | * |
| 6 | * Copyright (C) 2009 ST Microelectronics |
| 7 | * Viresh Kumar<viresh.kumar@st.com> |
| 8 | * |
| 9 | * This file is licensed under the terms of the GNU General Public |
| 10 | * License version 2. This program is licensed "as is" without any |
| 11 | * warranty of any kind, whether express or implied. |
| 12 | */ |
| 13 | |
| 14 | #include <linux/bug.h> |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 15 | #include <linux/clk.h> |
Shiraz Hashim | 4b9502e | 2011-02-16 07:40:40 +0100 | [diff] [blame] | 16 | #include <linux/debugfs.h> |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 17 | #include <linux/err.h> |
| 18 | #include <linux/io.h> |
| 19 | #include <linux/list.h> |
| 20 | #include <linux/module.h> |
| 21 | #include <linux/spinlock.h> |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 22 | #include <plat/clock.h> |
| 23 | |
| 24 | static DEFINE_SPINLOCK(clocks_lock); |
| 25 | static LIST_HEAD(root_clks); |
Shiraz Hashim | 4b9502e | 2011-02-16 07:40:40 +0100 | [diff] [blame] | 26 | #ifdef CONFIG_DEBUG_FS |
| 27 | static LIST_HEAD(clocks); |
| 28 | #endif |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 29 | |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 30 | static void propagate_rate(struct clk *, int on_init); |
Shiraz Hashim | 4b9502e | 2011-02-16 07:40:40 +0100 | [diff] [blame] | 31 | #ifdef CONFIG_DEBUG_FS |
| 32 | static int clk_debugfs_reparent(struct clk *); |
| 33 | #endif |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 34 | |
| 35 | static int generic_clk_enable(struct clk *clk) |
| 36 | { |
| 37 | unsigned int val; |
| 38 | |
| 39 | if (!clk->en_reg) |
| 40 | return -EFAULT; |
| 41 | |
| 42 | val = readl(clk->en_reg); |
| 43 | if (unlikely(clk->flags & RESET_TO_ENABLE)) |
| 44 | val &= ~(1 << clk->en_reg_bit); |
| 45 | else |
| 46 | val |= 1 << clk->en_reg_bit; |
| 47 | |
| 48 | writel(val, clk->en_reg); |
| 49 | |
| 50 | return 0; |
| 51 | } |
| 52 | |
| 53 | static void generic_clk_disable(struct clk *clk) |
| 54 | { |
| 55 | unsigned int val; |
| 56 | |
| 57 | if (!clk->en_reg) |
| 58 | return; |
| 59 | |
| 60 | val = readl(clk->en_reg); |
| 61 | if (unlikely(clk->flags & RESET_TO_ENABLE)) |
| 62 | val |= 1 << clk->en_reg_bit; |
| 63 | else |
| 64 | val &= ~(1 << clk->en_reg_bit); |
| 65 | |
| 66 | writel(val, clk->en_reg); |
| 67 | } |
| 68 | |
| 69 | /* generic clk ops */ |
| 70 | static struct clkops generic_clkops = { |
| 71 | .enable = generic_clk_enable, |
| 72 | .disable = generic_clk_disable, |
| 73 | }; |
| 74 | |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 75 | /* returns current programmed clocks clock info structure */ |
| 76 | static struct pclk_info *pclk_info_get(struct clk *clk) |
| 77 | { |
| 78 | unsigned int val, i; |
| 79 | struct pclk_info *info = NULL; |
| 80 | |
| 81 | val = (readl(clk->pclk_sel->pclk_sel_reg) >> clk->pclk_sel_shift) |
| 82 | & clk->pclk_sel->pclk_sel_mask; |
| 83 | |
| 84 | for (i = 0; i < clk->pclk_sel->pclk_count; i++) { |
| 85 | if (clk->pclk_sel->pclk_info[i].pclk_val == val) |
| 86 | info = &clk->pclk_sel->pclk_info[i]; |
| 87 | } |
| 88 | |
| 89 | return info; |
| 90 | } |
| 91 | |
| 92 | /* |
| 93 | * Set Update pclk, and pclk_info of clk and add clock sibling node to current |
| 94 | * parents children list |
| 95 | */ |
| 96 | static void clk_reparent(struct clk *clk, struct pclk_info *pclk_info) |
| 97 | { |
| 98 | unsigned long flags; |
| 99 | |
| 100 | spin_lock_irqsave(&clocks_lock, flags); |
| 101 | list_del(&clk->sibling); |
| 102 | list_add(&clk->sibling, &pclk_info->pclk->children); |
| 103 | |
| 104 | clk->pclk = pclk_info->pclk; |
| 105 | spin_unlock_irqrestore(&clocks_lock, flags); |
Shiraz Hashim | 4b9502e | 2011-02-16 07:40:40 +0100 | [diff] [blame] | 106 | |
| 107 | #ifdef CONFIG_DEBUG_FS |
| 108 | clk_debugfs_reparent(clk); |
| 109 | #endif |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 110 | } |
| 111 | |
| 112 | static void do_clk_disable(struct clk *clk) |
| 113 | { |
| 114 | if (!clk) |
| 115 | return; |
| 116 | |
| 117 | if (!clk->usage_count) { |
| 118 | WARN_ON(1); |
| 119 | return; |
| 120 | } |
| 121 | |
| 122 | clk->usage_count--; |
| 123 | |
| 124 | if (clk->usage_count == 0) { |
| 125 | /* |
| 126 | * Surely, there are no active childrens or direct users |
| 127 | * of this clock |
| 128 | */ |
| 129 | if (clk->pclk) |
| 130 | do_clk_disable(clk->pclk); |
| 131 | |
| 132 | if (clk->ops && clk->ops->disable) |
| 133 | clk->ops->disable(clk); |
| 134 | } |
| 135 | } |
| 136 | |
| 137 | static int do_clk_enable(struct clk *clk) |
| 138 | { |
| 139 | int ret = 0; |
| 140 | |
| 141 | if (!clk) |
| 142 | return -EFAULT; |
| 143 | |
| 144 | if (clk->usage_count == 0) { |
| 145 | if (clk->pclk) { |
| 146 | ret = do_clk_enable(clk->pclk); |
| 147 | if (ret) |
| 148 | goto err; |
| 149 | } |
| 150 | if (clk->ops && clk->ops->enable) { |
| 151 | ret = clk->ops->enable(clk); |
| 152 | if (ret) { |
| 153 | if (clk->pclk) |
| 154 | do_clk_disable(clk->pclk); |
| 155 | goto err; |
| 156 | } |
| 157 | } |
| 158 | /* |
| 159 | * Since the clock is going to be used for the first |
| 160 | * time please reclac |
| 161 | */ |
| 162 | if (clk->recalc) { |
| 163 | ret = clk->recalc(clk); |
| 164 | if (ret) |
| 165 | goto err; |
| 166 | } |
| 167 | } |
| 168 | clk->usage_count++; |
| 169 | err: |
| 170 | return ret; |
| 171 | } |
| 172 | |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 173 | /* |
| 174 | * clk_enable - inform the system when the clock source should be running. |
| 175 | * @clk: clock source |
| 176 | * |
| 177 | * If the clock can not be enabled/disabled, this should return success. |
| 178 | * |
| 179 | * Returns success (0) or negative errno. |
| 180 | */ |
| 181 | int clk_enable(struct clk *clk) |
| 182 | { |
| 183 | unsigned long flags; |
| 184 | int ret = 0; |
| 185 | |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 186 | spin_lock_irqsave(&clocks_lock, flags); |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 187 | ret = do_clk_enable(clk); |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 188 | spin_unlock_irqrestore(&clocks_lock, flags); |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 189 | return ret; |
| 190 | } |
| 191 | EXPORT_SYMBOL(clk_enable); |
| 192 | |
| 193 | /* |
| 194 | * clk_disable - inform the system when the clock source is no longer required. |
| 195 | * @clk: clock source |
| 196 | * |
| 197 | * Inform the system that a clock source is no longer required by |
| 198 | * a driver and may be shut down. |
| 199 | * |
| 200 | * Implementation detail: if the clock source is shared between |
| 201 | * multiple drivers, clk_enable() calls must be balanced by the |
| 202 | * same number of clk_disable() calls for the clock source to be |
| 203 | * disabled. |
| 204 | */ |
| 205 | void clk_disable(struct clk *clk) |
| 206 | { |
| 207 | unsigned long flags; |
| 208 | |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 209 | spin_lock_irqsave(&clocks_lock, flags); |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 210 | do_clk_disable(clk); |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 211 | spin_unlock_irqrestore(&clocks_lock, flags); |
| 212 | } |
| 213 | EXPORT_SYMBOL(clk_disable); |
| 214 | |
| 215 | /** |
| 216 | * clk_get_rate - obtain the current clock rate (in Hz) for a clock source. |
| 217 | * This is only valid once the clock source has been enabled. |
| 218 | * @clk: clock source |
| 219 | */ |
| 220 | unsigned long clk_get_rate(struct clk *clk) |
| 221 | { |
| 222 | unsigned long flags, rate; |
| 223 | |
| 224 | spin_lock_irqsave(&clocks_lock, flags); |
| 225 | rate = clk->rate; |
| 226 | spin_unlock_irqrestore(&clocks_lock, flags); |
| 227 | |
| 228 | return rate; |
| 229 | } |
| 230 | EXPORT_SYMBOL(clk_get_rate); |
| 231 | |
| 232 | /** |
| 233 | * clk_set_parent - set the parent clock source for this clock |
| 234 | * @clk: clock source |
| 235 | * @parent: parent clock source |
| 236 | * |
| 237 | * Returns success (0) or negative errno. |
| 238 | */ |
| 239 | int clk_set_parent(struct clk *clk, struct clk *parent) |
| 240 | { |
| 241 | int i, found = 0, val = 0; |
| 242 | unsigned long flags; |
| 243 | |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 244 | if (!clk || !parent) |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 245 | return -EFAULT; |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 246 | if (clk->pclk == parent) |
| 247 | return 0; |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 248 | if (!clk->pclk_sel) |
| 249 | return -EPERM; |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 250 | |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 251 | /* check if requested parent is in clk parent list */ |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 252 | for (i = 0; i < clk->pclk_sel->pclk_count; i++) { |
| 253 | if (clk->pclk_sel->pclk_info[i].pclk == parent) { |
| 254 | found = 1; |
| 255 | break; |
| 256 | } |
| 257 | } |
| 258 | |
| 259 | if (!found) |
| 260 | return -EINVAL; |
| 261 | |
| 262 | spin_lock_irqsave(&clocks_lock, flags); |
| 263 | /* reflect parent change in hardware */ |
| 264 | val = readl(clk->pclk_sel->pclk_sel_reg); |
| 265 | val &= ~(clk->pclk_sel->pclk_sel_mask << clk->pclk_sel_shift); |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 266 | val |= clk->pclk_sel->pclk_info[i].pclk_val << clk->pclk_sel_shift; |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 267 | writel(val, clk->pclk_sel->pclk_sel_reg); |
| 268 | spin_unlock_irqrestore(&clocks_lock, flags); |
| 269 | |
| 270 | /* reflect parent change in software */ |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 271 | clk_reparent(clk, &clk->pclk_sel->pclk_info[i]); |
| 272 | |
| 273 | propagate_rate(clk, 0); |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 274 | return 0; |
| 275 | } |
| 276 | EXPORT_SYMBOL(clk_set_parent); |
| 277 | |
viresh kumar | cf28543 | 2011-02-16 07:40:31 +0100 | [diff] [blame] | 278 | /** |
| 279 | * clk_set_rate - set the clock rate for a clock source |
| 280 | * @clk: clock source |
| 281 | * @rate: desired clock rate in Hz |
| 282 | * |
| 283 | * Returns success (0) or negative errno. |
| 284 | */ |
| 285 | int clk_set_rate(struct clk *clk, unsigned long rate) |
| 286 | { |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 287 | unsigned long flags; |
| 288 | int ret = -EINVAL; |
| 289 | |
| 290 | if (!clk || !rate) |
| 291 | return -EFAULT; |
| 292 | |
| 293 | if (clk->set_rate) { |
| 294 | spin_lock_irqsave(&clocks_lock, flags); |
| 295 | ret = clk->set_rate(clk, rate); |
| 296 | if (!ret) |
| 297 | /* if successful -> propagate */ |
| 298 | propagate_rate(clk, 0); |
| 299 | spin_unlock_irqrestore(&clocks_lock, flags); |
| 300 | } else if (clk->pclk) { |
| 301 | u32 mult = clk->div_factor ? clk->div_factor : 1; |
| 302 | ret = clk_set_rate(clk->pclk, mult * rate); |
| 303 | } |
| 304 | |
| 305 | return ret; |
viresh kumar | cf28543 | 2011-02-16 07:40:31 +0100 | [diff] [blame] | 306 | } |
| 307 | EXPORT_SYMBOL(clk_set_rate); |
| 308 | |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 309 | /* registers clock in platform clock framework */ |
| 310 | void clk_register(struct clk_lookup *cl) |
| 311 | { |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 312 | struct clk *clk; |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 313 | unsigned long flags; |
| 314 | |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 315 | if (!cl || !cl->clk) |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 316 | return; |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 317 | clk = cl->clk; |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 318 | |
| 319 | spin_lock_irqsave(&clocks_lock, flags); |
| 320 | |
| 321 | INIT_LIST_HEAD(&clk->children); |
| 322 | if (clk->flags & ALWAYS_ENABLED) |
| 323 | clk->ops = NULL; |
| 324 | else if (!clk->ops) |
| 325 | clk->ops = &generic_clkops; |
| 326 | |
| 327 | /* root clock don't have any parents */ |
| 328 | if (!clk->pclk && !clk->pclk_sel) { |
| 329 | list_add(&clk->sibling, &root_clks); |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 330 | } else if (clk->pclk && !clk->pclk_sel) { |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 331 | /* add clocks with only one parent to parent's children list */ |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 332 | list_add(&clk->sibling, &clk->pclk->children); |
| 333 | } else { |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 334 | /* clocks with more than one parent */ |
| 335 | struct pclk_info *pclk_info; |
| 336 | |
| 337 | pclk_info = pclk_info_get(clk); |
| 338 | if (!pclk_info) { |
| 339 | pr_err("CLKDEV: invalid pclk info of clk with" |
| 340 | " %s dev_id and %s con_id\n", |
| 341 | cl->dev_id, cl->con_id); |
| 342 | } else { |
| 343 | clk->pclk = pclk_info->pclk; |
| 344 | list_add(&clk->sibling, &pclk_info->pclk->children); |
| 345 | } |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 346 | } |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 347 | |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 348 | spin_unlock_irqrestore(&clocks_lock, flags); |
| 349 | |
Shiraz Hashim | 4b9502e | 2011-02-16 07:40:40 +0100 | [diff] [blame] | 350 | /* debugfs specific */ |
| 351 | #ifdef CONFIG_DEBUG_FS |
| 352 | list_add(&clk->node, &clocks); |
| 353 | clk->cl = cl; |
| 354 | #endif |
| 355 | |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 356 | /* add clock to arm clockdev framework */ |
| 357 | clkdev_add(cl); |
| 358 | } |
| 359 | |
| 360 | /** |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 361 | * propagate_rate - recalculate and propagate all clocks to children |
| 362 | * @pclk: parent clock required to be propogated |
| 363 | * @on_init: flag for enabling clocks which are ENABLED_ON_INIT. |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 364 | * |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 365 | * Recalculates all children clocks |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 366 | */ |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 367 | void propagate_rate(struct clk *pclk, int on_init) |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 368 | { |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 369 | struct clk *clk, *_temp; |
| 370 | int ret = 0; |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 371 | |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 372 | list_for_each_entry_safe(clk, _temp, &pclk->children, sibling) { |
| 373 | if (clk->recalc) { |
| 374 | ret = clk->recalc(clk); |
| 375 | /* |
| 376 | * recalc will return error if clk out is not programmed |
| 377 | * In this case configure default rate. |
| 378 | */ |
| 379 | if (ret && clk->set_rate) |
| 380 | clk->set_rate(clk, 0); |
| 381 | } |
| 382 | propagate_rate(clk, on_init); |
| 383 | |
| 384 | if (!on_init) |
| 385 | continue; |
| 386 | |
| 387 | /* Enable clks enabled on init, in software view */ |
| 388 | if (clk->flags & ENABLED_ON_INIT) |
| 389 | do_clk_enable(clk); |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 390 | } |
| 391 | } |
| 392 | |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 393 | /** |
| 394 | * round_rate_index - return closest programmable rate index in rate_config tbl |
| 395 | * @clk: ptr to clock structure |
| 396 | * @drate: desired rate |
| 397 | * @rate: final rate will be returned in this variable only. |
| 398 | * |
| 399 | * Finds index in rate_config for highest clk rate which is less than |
| 400 | * requested rate. If there is no clk rate lesser than requested rate then |
| 401 | * -EINVAL is returned. This routine assumes that rate_config is written |
| 402 | * in incrementing order of clk rates. |
| 403 | * If drate passed is zero then default rate is programmed. |
| 404 | */ |
| 405 | static int |
| 406 | round_rate_index(struct clk *clk, unsigned long drate, unsigned long *rate) |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 407 | { |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 408 | unsigned long tmp = 0, prev_rate = 0; |
| 409 | int index; |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 410 | |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 411 | if (!clk->calc_rate) |
| 412 | return -EFAULT; |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 413 | |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 414 | if (!drate) |
| 415 | return -EINVAL; |
| 416 | |
| 417 | /* |
| 418 | * This loops ends on two conditions: |
| 419 | * - as soon as clk is found with rate greater than requested rate. |
| 420 | * - if all clks in rate_config are smaller than requested rate. |
| 421 | */ |
| 422 | for (index = 0; index < clk->rate_config.count; index++) { |
| 423 | prev_rate = tmp; |
| 424 | tmp = clk->calc_rate(clk, index); |
| 425 | if (drate < tmp) { |
| 426 | index--; |
| 427 | break; |
| 428 | } |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 429 | } |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 430 | /* return if can't find suitable clock */ |
| 431 | if (index < 0) { |
| 432 | index = -EINVAL; |
| 433 | *rate = 0; |
| 434 | } else if (index == clk->rate_config.count) { |
| 435 | /* program with highest clk rate possible */ |
| 436 | index = clk->rate_config.count - 1; |
| 437 | *rate = tmp; |
| 438 | } else |
| 439 | *rate = prev_rate; |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 440 | |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 441 | return index; |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 442 | } |
| 443 | |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 444 | /** |
| 445 | * clk_round_rate - adjust a rate to the exact rate a clock can provide |
| 446 | * @clk: clock source |
| 447 | * @rate: desired clock rate in Hz |
| 448 | * |
| 449 | * Returns rounded clock rate in Hz, or negative errno. |
| 450 | */ |
| 451 | long clk_round_rate(struct clk *clk, unsigned long drate) |
| 452 | { |
| 453 | long rate = 0; |
| 454 | int index; |
| 455 | |
| 456 | /* |
| 457 | * propagate call to parent who supports calc_rate. Similar approach is |
| 458 | * used in clk_set_rate. |
| 459 | */ |
| 460 | if (!clk->calc_rate) { |
| 461 | u32 mult; |
| 462 | if (!clk->pclk) |
| 463 | return clk->rate; |
| 464 | |
| 465 | mult = clk->div_factor ? clk->div_factor : 1; |
| 466 | return clk_round_rate(clk->pclk, mult * drate) / mult; |
| 467 | } |
| 468 | |
| 469 | index = round_rate_index(clk, drate, &rate); |
| 470 | if (index >= 0) |
| 471 | return rate; |
| 472 | else |
| 473 | return index; |
| 474 | } |
| 475 | EXPORT_SYMBOL(clk_round_rate); |
| 476 | |
| 477 | /*All below functions are called with lock held */ |
| 478 | |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 479 | /* |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 480 | * Calculates pll clk rate for specific value of mode, m, n and p |
| 481 | * |
| 482 | * In normal mode |
| 483 | * rate = (2 * M[15:8] * Fin)/(N * 2^P) |
| 484 | * |
| 485 | * In Dithered mode |
| 486 | * rate = (2 * M[15:0] * Fin)/(256 * N * 2^P) |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 487 | */ |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 488 | unsigned long pll_calc_rate(struct clk *clk, int index) |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 489 | { |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 490 | unsigned long rate = clk->pclk->rate; |
| 491 | struct pll_rate_tbl *tbls = clk->rate_config.tbls; |
| 492 | unsigned int mode; |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 493 | |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 494 | mode = tbls[index].mode ? 256 : 1; |
| 495 | return (((2 * rate / 10000) * tbls[index].m) / |
| 496 | (mode * tbls[index].n * (1 << tbls[index].p))) * 10000; |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 497 | } |
| 498 | |
| 499 | /* |
| 500 | * calculates current programmed rate of pll1 |
| 501 | * |
| 502 | * In normal mode |
| 503 | * rate = (2 * M[15:8] * Fin)/(N * 2^P) |
| 504 | * |
| 505 | * In Dithered mode |
| 506 | * rate = (2 * M[15:0] * Fin)/(256 * N * 2^P) |
| 507 | */ |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 508 | int pll_clk_recalc(struct clk *clk) |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 509 | { |
| 510 | struct pll_clk_config *config = clk->private_data; |
| 511 | unsigned int num = 2, den = 0, val, mode = 0; |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 512 | |
viresh kumar | cf28543 | 2011-02-16 07:40:31 +0100 | [diff] [blame] | 513 | mode = (readl(config->mode_reg) >> config->masks->mode_shift) & |
| 514 | config->masks->mode_mask; |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 515 | |
| 516 | val = readl(config->cfg_reg); |
| 517 | /* calculate denominator */ |
viresh kumar | cf28543 | 2011-02-16 07:40:31 +0100 | [diff] [blame] | 518 | den = (val >> config->masks->div_p_shift) & config->masks->div_p_mask; |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 519 | den = 1 << den; |
viresh kumar | cf28543 | 2011-02-16 07:40:31 +0100 | [diff] [blame] | 520 | den *= (val >> config->masks->div_n_shift) & config->masks->div_n_mask; |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 521 | |
| 522 | /* calculate numerator & denominator */ |
| 523 | if (!mode) { |
| 524 | /* Normal mode */ |
viresh kumar | cf28543 | 2011-02-16 07:40:31 +0100 | [diff] [blame] | 525 | num *= (val >> config->masks->norm_fdbk_m_shift) & |
| 526 | config->masks->norm_fdbk_m_mask; |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 527 | } else { |
| 528 | /* Dithered mode */ |
viresh kumar | cf28543 | 2011-02-16 07:40:31 +0100 | [diff] [blame] | 529 | num *= (val >> config->masks->dith_fdbk_m_shift) & |
| 530 | config->masks->dith_fdbk_m_mask; |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 531 | den *= 256; |
| 532 | } |
| 533 | |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 534 | if (!den) |
| 535 | return -EINVAL; |
| 536 | |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 537 | clk->rate = (((clk->pclk->rate/10000) * num) / den) * 10000; |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 538 | return 0; |
| 539 | } |
| 540 | |
| 541 | /* |
| 542 | * Configures new clock rate of pll |
| 543 | */ |
| 544 | int pll_clk_set_rate(struct clk *clk, unsigned long desired_rate) |
| 545 | { |
| 546 | struct pll_rate_tbl *tbls = clk->rate_config.tbls; |
| 547 | struct pll_clk_config *config = clk->private_data; |
| 548 | unsigned long val, rate; |
| 549 | int i; |
| 550 | |
| 551 | i = round_rate_index(clk, desired_rate, &rate); |
| 552 | if (i < 0) |
| 553 | return i; |
| 554 | |
| 555 | val = readl(config->mode_reg) & |
| 556 | ~(config->masks->mode_mask << config->masks->mode_shift); |
| 557 | val |= (tbls[i].mode & config->masks->mode_mask) << |
| 558 | config->masks->mode_shift; |
| 559 | writel(val, config->mode_reg); |
| 560 | |
| 561 | val = readl(config->cfg_reg) & |
| 562 | ~(config->masks->div_p_mask << config->masks->div_p_shift); |
| 563 | val |= (tbls[i].p & config->masks->div_p_mask) << |
| 564 | config->masks->div_p_shift; |
| 565 | val &= ~(config->masks->div_n_mask << config->masks->div_n_shift); |
| 566 | val |= (tbls[i].n & config->masks->div_n_mask) << |
| 567 | config->masks->div_n_shift; |
| 568 | val &= ~(config->masks->dith_fdbk_m_mask << |
| 569 | config->masks->dith_fdbk_m_shift); |
| 570 | if (tbls[i].mode) |
| 571 | val |= (tbls[i].m & config->masks->dith_fdbk_m_mask) << |
| 572 | config->masks->dith_fdbk_m_shift; |
| 573 | else |
| 574 | val |= (tbls[i].m & config->masks->norm_fdbk_m_mask) << |
| 575 | config->masks->norm_fdbk_m_shift; |
| 576 | |
| 577 | writel(val, config->cfg_reg); |
| 578 | |
| 579 | clk->rate = rate; |
| 580 | |
| 581 | return 0; |
| 582 | } |
| 583 | |
| 584 | /* |
| 585 | * Calculates ahb, apb clk rate for specific value of div |
| 586 | */ |
| 587 | unsigned long bus_calc_rate(struct clk *clk, int index) |
| 588 | { |
| 589 | unsigned long rate = clk->pclk->rate; |
| 590 | struct bus_rate_tbl *tbls = clk->rate_config.tbls; |
| 591 | |
| 592 | return rate / (tbls[index].div + 1); |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 593 | } |
| 594 | |
| 595 | /* calculates current programmed rate of ahb or apb bus */ |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 596 | int bus_clk_recalc(struct clk *clk) |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 597 | { |
| 598 | struct bus_clk_config *config = clk->private_data; |
| 599 | unsigned int div; |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 600 | |
viresh kumar | cf28543 | 2011-02-16 07:40:31 +0100 | [diff] [blame] | 601 | div = ((readl(config->reg) >> config->masks->shift) & |
| 602 | config->masks->mask) + 1; |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 603 | |
| 604 | if (!div) |
| 605 | return -EINVAL; |
| 606 | |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 607 | clk->rate = (unsigned long)clk->pclk->rate / div; |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 608 | return 0; |
| 609 | } |
| 610 | |
| 611 | /* Configures new clock rate of AHB OR APB bus */ |
| 612 | int bus_clk_set_rate(struct clk *clk, unsigned long desired_rate) |
| 613 | { |
| 614 | struct bus_rate_tbl *tbls = clk->rate_config.tbls; |
| 615 | struct bus_clk_config *config = clk->private_data; |
| 616 | unsigned long val, rate; |
| 617 | int i; |
| 618 | |
| 619 | i = round_rate_index(clk, desired_rate, &rate); |
| 620 | if (i < 0) |
| 621 | return i; |
| 622 | |
| 623 | val = readl(config->reg) & |
| 624 | ~(config->masks->mask << config->masks->shift); |
| 625 | val |= (tbls[i].div & config->masks->mask) << config->masks->shift; |
| 626 | writel(val, config->reg); |
| 627 | |
| 628 | clk->rate = rate; |
| 629 | |
| 630 | return 0; |
| 631 | } |
| 632 | |
| 633 | /* |
| 634 | * gives rate for different values of eq, x and y |
| 635 | * |
| 636 | * Fout from synthesizer can be given from two equations: |
| 637 | * Fout1 = (Fin * X/Y)/2 EQ1 |
| 638 | * Fout2 = Fin * X/Y EQ2 |
| 639 | */ |
| 640 | unsigned long aux_calc_rate(struct clk *clk, int index) |
| 641 | { |
| 642 | unsigned long rate = clk->pclk->rate; |
| 643 | struct aux_rate_tbl *tbls = clk->rate_config.tbls; |
| 644 | u8 eq = tbls[index].eq ? 1 : 2; |
| 645 | |
| 646 | return (((rate/10000) * tbls[index].xscale) / |
| 647 | (tbls[index].yscale * eq)) * 10000; |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 648 | } |
| 649 | |
| 650 | /* |
| 651 | * calculates current programmed rate of auxiliary synthesizers |
| 652 | * used by: UART, FIRDA |
| 653 | * |
| 654 | * Fout from synthesizer can be given from two equations: |
| 655 | * Fout1 = (Fin * X/Y)/2 |
| 656 | * Fout2 = Fin * X/Y |
| 657 | * |
| 658 | * Selection of eqn 1 or 2 is programmed in register |
| 659 | */ |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 660 | int aux_clk_recalc(struct clk *clk) |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 661 | { |
| 662 | struct aux_clk_config *config = clk->private_data; |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 663 | unsigned int num = 1, den = 1, val, eqn; |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 664 | |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 665 | val = readl(config->synth_reg); |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 666 | |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 667 | eqn = (val >> config->masks->eq_sel_shift) & |
| 668 | config->masks->eq_sel_mask; |
| 669 | if (eqn == config->masks->eq1_mask) |
| 670 | den *= 2; |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 671 | |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 672 | /* calculate numerator */ |
| 673 | num = (val >> config->masks->xscale_sel_shift) & |
| 674 | config->masks->xscale_sel_mask; |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 675 | |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 676 | /* calculate denominator */ |
| 677 | den *= (val >> config->masks->yscale_sel_shift) & |
| 678 | config->masks->yscale_sel_mask; |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 679 | |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 680 | if (!den) |
| 681 | return -EINVAL; |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 682 | |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 683 | clk->rate = (((clk->pclk->rate/10000) * num) / den) * 10000; |
| 684 | return 0; |
| 685 | } |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 686 | |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 687 | /* Configures new clock rate of auxiliary synthesizers used by: UART, FIRDA*/ |
| 688 | int aux_clk_set_rate(struct clk *clk, unsigned long desired_rate) |
| 689 | { |
| 690 | struct aux_rate_tbl *tbls = clk->rate_config.tbls; |
| 691 | struct aux_clk_config *config = clk->private_data; |
| 692 | unsigned long val, rate; |
| 693 | int i; |
| 694 | |
| 695 | i = round_rate_index(clk, desired_rate, &rate); |
| 696 | if (i < 0) |
| 697 | return i; |
| 698 | |
| 699 | val = readl(config->synth_reg) & |
| 700 | ~(config->masks->eq_sel_mask << config->masks->eq_sel_shift); |
| 701 | val |= (tbls[i].eq & config->masks->eq_sel_mask) << |
| 702 | config->masks->eq_sel_shift; |
| 703 | val &= ~(config->masks->xscale_sel_mask << |
| 704 | config->masks->xscale_sel_shift); |
| 705 | val |= (tbls[i].xscale & config->masks->xscale_sel_mask) << |
| 706 | config->masks->xscale_sel_shift; |
| 707 | val &= ~(config->masks->yscale_sel_mask << |
| 708 | config->masks->yscale_sel_shift); |
| 709 | val |= (tbls[i].yscale & config->masks->yscale_sel_mask) << |
| 710 | config->masks->yscale_sel_shift; |
| 711 | writel(val, config->synth_reg); |
| 712 | |
| 713 | clk->rate = rate; |
| 714 | |
| 715 | return 0; |
| 716 | } |
| 717 | |
| 718 | /* |
| 719 | * Calculates gpt clk rate for different values of mscale and nscale |
| 720 | * |
| 721 | * Fout= Fin/((2 ^ (N+1)) * (M+1)) |
| 722 | */ |
| 723 | unsigned long gpt_calc_rate(struct clk *clk, int index) |
| 724 | { |
| 725 | unsigned long rate = clk->pclk->rate; |
| 726 | struct gpt_rate_tbl *tbls = clk->rate_config.tbls; |
| 727 | |
| 728 | return rate / ((1 << (tbls[index].nscale + 1)) * |
| 729 | (tbls[index].mscale + 1)); |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 730 | } |
| 731 | |
| 732 | /* |
| 733 | * calculates current programmed rate of gpt synthesizers |
| 734 | * Fout from synthesizer can be given from below equations: |
| 735 | * Fout= Fin/((2 ^ (N+1)) * (M+1)) |
| 736 | */ |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 737 | int gpt_clk_recalc(struct clk *clk) |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 738 | { |
viresh kumar | cf28543 | 2011-02-16 07:40:31 +0100 | [diff] [blame] | 739 | struct gpt_clk_config *config = clk->private_data; |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 740 | unsigned int div = 1, val; |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 741 | |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 742 | val = readl(config->synth_reg); |
| 743 | div += (val >> config->masks->mscale_sel_shift) & |
| 744 | config->masks->mscale_sel_mask; |
| 745 | div *= 1 << (((val >> config->masks->nscale_sel_shift) & |
| 746 | config->masks->nscale_sel_mask) + 1); |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 747 | |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 748 | if (!div) |
| 749 | return -EINVAL; |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 750 | |
| 751 | clk->rate = (unsigned long)clk->pclk->rate / div; |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 752 | return 0; |
| 753 | } |
| 754 | |
| 755 | /* Configures new clock rate of gptiliary synthesizers used by: UART, FIRDA*/ |
| 756 | int gpt_clk_set_rate(struct clk *clk, unsigned long desired_rate) |
| 757 | { |
| 758 | struct gpt_rate_tbl *tbls = clk->rate_config.tbls; |
| 759 | struct gpt_clk_config *config = clk->private_data; |
| 760 | unsigned long val, rate; |
| 761 | int i; |
| 762 | |
| 763 | i = round_rate_index(clk, desired_rate, &rate); |
| 764 | if (i < 0) |
| 765 | return i; |
| 766 | |
| 767 | val = readl(config->synth_reg) & ~(config->masks->mscale_sel_mask << |
| 768 | config->masks->mscale_sel_shift); |
| 769 | val |= (tbls[i].mscale & config->masks->mscale_sel_mask) << |
| 770 | config->masks->mscale_sel_shift; |
| 771 | val &= ~(config->masks->nscale_sel_mask << |
| 772 | config->masks->nscale_sel_shift); |
| 773 | val |= (tbls[i].nscale & config->masks->nscale_sel_mask) << |
| 774 | config->masks->nscale_sel_shift; |
| 775 | writel(val, config->synth_reg); |
| 776 | |
| 777 | clk->rate = rate; |
| 778 | |
| 779 | return 0; |
| 780 | } |
| 781 | |
| 782 | /* |
| 783 | * Calculates clcd clk rate for different values of div |
| 784 | * |
| 785 | * Fout from synthesizer can be given from below equation: |
| 786 | * Fout= Fin/2*div (division factor) |
| 787 | * div is 17 bits:- |
| 788 | * 0-13 (fractional part) |
| 789 | * 14-16 (integer part) |
| 790 | * To calculate Fout we left shift val by 14 bits and divide Fin by |
| 791 | * complete div (including fractional part) and then right shift the |
| 792 | * result by 14 places. |
| 793 | */ |
| 794 | unsigned long clcd_calc_rate(struct clk *clk, int index) |
| 795 | { |
| 796 | unsigned long rate = clk->pclk->rate; |
| 797 | struct clcd_rate_tbl *tbls = clk->rate_config.tbls; |
| 798 | |
| 799 | rate /= 1000; |
| 800 | rate <<= 12; |
| 801 | rate /= (2 * tbls[index].div); |
| 802 | rate >>= 12; |
| 803 | rate *= 1000; |
| 804 | |
| 805 | return rate; |
| 806 | } |
| 807 | |
| 808 | /* |
| 809 | * calculates current programmed rate of clcd synthesizer |
| 810 | * Fout from synthesizer can be given from below equation: |
| 811 | * Fout= Fin/2*div (division factor) |
| 812 | * div is 17 bits:- |
| 813 | * 0-13 (fractional part) |
| 814 | * 14-16 (integer part) |
| 815 | * To calculate Fout we left shift val by 14 bits and divide Fin by |
| 816 | * complete div (including fractional part) and then right shift the |
| 817 | * result by 14 places. |
| 818 | */ |
| 819 | int clcd_clk_recalc(struct clk *clk) |
| 820 | { |
| 821 | struct clcd_clk_config *config = clk->private_data; |
| 822 | unsigned int div = 1; |
| 823 | unsigned long prate; |
| 824 | unsigned int val; |
| 825 | |
| 826 | val = readl(config->synth_reg); |
| 827 | div = (val >> config->masks->div_factor_shift) & |
| 828 | config->masks->div_factor_mask; |
| 829 | |
| 830 | if (!div) |
| 831 | return -EINVAL; |
| 832 | |
| 833 | prate = clk->pclk->rate / 1000; /* first level division, make it KHz */ |
| 834 | |
| 835 | clk->rate = (((unsigned long)prate << 12) / (2 * div)) >> 12; |
| 836 | clk->rate *= 1000; |
| 837 | return 0; |
| 838 | } |
| 839 | |
| 840 | /* Configures new clock rate of auxiliary synthesizers used by: UART, FIRDA*/ |
| 841 | int clcd_clk_set_rate(struct clk *clk, unsigned long desired_rate) |
| 842 | { |
| 843 | struct clcd_rate_tbl *tbls = clk->rate_config.tbls; |
| 844 | struct clcd_clk_config *config = clk->private_data; |
| 845 | unsigned long val, rate; |
| 846 | int i; |
| 847 | |
| 848 | i = round_rate_index(clk, desired_rate, &rate); |
| 849 | if (i < 0) |
| 850 | return i; |
| 851 | |
| 852 | val = readl(config->synth_reg) & ~(config->masks->div_factor_mask << |
| 853 | config->masks->div_factor_shift); |
| 854 | val |= (tbls[i].div & config->masks->div_factor_mask) << |
| 855 | config->masks->div_factor_shift; |
| 856 | writel(val, config->synth_reg); |
| 857 | |
| 858 | clk->rate = rate; |
| 859 | |
| 860 | return 0; |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 861 | } |
| 862 | |
| 863 | /* |
viresh kumar | cf28543 | 2011-02-16 07:40:31 +0100 | [diff] [blame] | 864 | * Used for clocks that always have value as the parent clock divided by a |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 865 | * fixed divisor |
| 866 | */ |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 867 | int follow_parent(struct clk *clk) |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 868 | { |
viresh kumar | cf28543 | 2011-02-16 07:40:31 +0100 | [diff] [blame] | 869 | unsigned int div_factor = (clk->div_factor < 1) ? 1 : clk->div_factor; |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 870 | |
viresh kumar | cf28543 | 2011-02-16 07:40:31 +0100 | [diff] [blame] | 871 | clk->rate = clk->pclk->rate/div_factor; |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 872 | return 0; |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 873 | } |
| 874 | |
| 875 | /** |
| 876 | * recalc_root_clocks - recalculate and propagate all root clocks |
| 877 | * |
| 878 | * Recalculates all root clocks (clocks with no parent), which if the |
| 879 | * clock's .recalc is set correctly, should also propagate their rates. |
| 880 | */ |
| 881 | void recalc_root_clocks(void) |
| 882 | { |
viresh kumar | af89fd8 | 2011-02-16 07:40:39 +0100 | [diff] [blame] | 883 | struct clk *pclk; |
| 884 | unsigned long flags; |
| 885 | int ret = 0; |
| 886 | |
| 887 | spin_lock_irqsave(&clocks_lock, flags); |
| 888 | list_for_each_entry(pclk, &root_clks, sibling) { |
| 889 | if (pclk->recalc) { |
| 890 | ret = pclk->recalc(pclk); |
| 891 | /* |
| 892 | * recalc will return error if clk out is not programmed |
| 893 | * In this case configure default clock. |
| 894 | */ |
| 895 | if (ret && pclk->set_rate) |
| 896 | pclk->set_rate(pclk, 0); |
| 897 | } |
| 898 | propagate_rate(pclk, 1); |
| 899 | /* Enable clks enabled on init, in software view */ |
| 900 | if (pclk->flags & ENABLED_ON_INIT) |
| 901 | do_clk_enable(pclk); |
| 902 | } |
| 903 | spin_unlock_irqrestore(&clocks_lock, flags); |
viresh kumar | 8c0236f | 2010-04-01 12:30:46 +0100 | [diff] [blame] | 904 | } |
Shiraz Hashim | 4b9502e | 2011-02-16 07:40:40 +0100 | [diff] [blame] | 905 | |
viresh kumar | b997f6e | 2011-05-20 08:34:18 +0100 | [diff] [blame] | 906 | void __init clk_init(void) |
| 907 | { |
| 908 | recalc_root_clocks(); |
| 909 | } |
| 910 | |
Shiraz Hashim | 4b9502e | 2011-02-16 07:40:40 +0100 | [diff] [blame] | 911 | #ifdef CONFIG_DEBUG_FS |
| 912 | /* |
| 913 | * debugfs support to trace clock tree hierarchy and attributes |
| 914 | */ |
| 915 | static struct dentry *clk_debugfs_root; |
| 916 | static int clk_debugfs_register_one(struct clk *c) |
| 917 | { |
| 918 | int err; |
| 919 | struct dentry *d, *child; |
| 920 | struct clk *pa = c->pclk; |
| 921 | char s[255]; |
| 922 | char *p = s; |
| 923 | |
| 924 | if (c) { |
| 925 | if (c->cl->con_id) |
| 926 | p += sprintf(p, "%s", c->cl->con_id); |
| 927 | if (c->cl->dev_id) |
| 928 | p += sprintf(p, "%s", c->cl->dev_id); |
| 929 | } |
| 930 | d = debugfs_create_dir(s, pa ? pa->dent : clk_debugfs_root); |
| 931 | if (!d) |
| 932 | return -ENOMEM; |
| 933 | c->dent = d; |
| 934 | |
| 935 | d = debugfs_create_u32("usage_count", S_IRUGO, c->dent, |
| 936 | (u32 *)&c->usage_count); |
| 937 | if (!d) { |
| 938 | err = -ENOMEM; |
| 939 | goto err_out; |
| 940 | } |
| 941 | d = debugfs_create_u32("rate", S_IRUGO, c->dent, (u32 *)&c->rate); |
| 942 | if (!d) { |
| 943 | err = -ENOMEM; |
| 944 | goto err_out; |
| 945 | } |
| 946 | d = debugfs_create_x32("flags", S_IRUGO, c->dent, (u32 *)&c->flags); |
| 947 | if (!d) { |
| 948 | err = -ENOMEM; |
| 949 | goto err_out; |
| 950 | } |
| 951 | return 0; |
| 952 | |
| 953 | err_out: |
| 954 | d = c->dent; |
| 955 | list_for_each_entry(child, &d->d_subdirs, d_u.d_child) |
| 956 | debugfs_remove(child); |
| 957 | debugfs_remove(c->dent); |
| 958 | return err; |
| 959 | } |
| 960 | |
| 961 | static int clk_debugfs_register(struct clk *c) |
| 962 | { |
| 963 | int err; |
| 964 | struct clk *pa = c->pclk; |
| 965 | |
| 966 | if (pa && !pa->dent) { |
| 967 | err = clk_debugfs_register(pa); |
| 968 | if (err) |
| 969 | return err; |
| 970 | } |
| 971 | |
| 972 | if (!c->dent) { |
| 973 | err = clk_debugfs_register_one(c); |
| 974 | if (err) |
| 975 | return err; |
| 976 | } |
| 977 | return 0; |
| 978 | } |
| 979 | |
| 980 | static int __init clk_debugfs_init(void) |
| 981 | { |
| 982 | struct clk *c; |
| 983 | struct dentry *d; |
| 984 | int err; |
| 985 | |
| 986 | d = debugfs_create_dir("clock", NULL); |
| 987 | if (!d) |
| 988 | return -ENOMEM; |
| 989 | clk_debugfs_root = d; |
| 990 | |
| 991 | list_for_each_entry(c, &clocks, node) { |
| 992 | err = clk_debugfs_register(c); |
| 993 | if (err) |
| 994 | goto err_out; |
| 995 | } |
| 996 | return 0; |
| 997 | err_out: |
| 998 | debugfs_remove_recursive(clk_debugfs_root); |
| 999 | return err; |
| 1000 | } |
| 1001 | late_initcall(clk_debugfs_init); |
| 1002 | |
| 1003 | static int clk_debugfs_reparent(struct clk *c) |
| 1004 | { |
| 1005 | debugfs_remove(c->dent); |
| 1006 | return clk_debugfs_register_one(c); |
| 1007 | } |
| 1008 | #endif /* CONFIG_DEBUG_FS */ |