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