clock.c (ecf0aa5317b0ad6bb015128a5b763c954fd58708) | clock.c (c73b9099da4fb5703abaa804a0377850eea66cb5) |
---|---|
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * linux/arch/arm/mach-omap1/clock.c 4 * 5 * Copyright (C) 2004 - 2005, 2009-2010 Nokia Corporation 6 * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> 7 * 8 * Modified to use omap shared clock framework by 9 * Tony Lindgren <tony@atomide.com> 10 */ 11#include <linux/kernel.h> 12#include <linux/export.h> 13#include <linux/list.h> 14#include <linux/errno.h> 15#include <linux/err.h> 16#include <linux/io.h> 17#include <linux/clk.h> 18#include <linux/clkdev.h> | 1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * linux/arch/arm/mach-omap1/clock.c 4 * 5 * Copyright (C) 2004 - 2005, 2009-2010 Nokia Corporation 6 * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> 7 * 8 * Modified to use omap shared clock framework by 9 * Tony Lindgren <tony@atomide.com> 10 */ 11#include <linux/kernel.h> 12#include <linux/export.h> 13#include <linux/list.h> 14#include <linux/errno.h> 15#include <linux/err.h> 16#include <linux/io.h> 17#include <linux/clk.h> 18#include <linux/clkdev.h> |
19#include <linux/clk-provider.h> |
|
19#include <linux/soc/ti/omap1-io.h> | 20#include <linux/soc/ti/omap1-io.h> |
21#include <linux/spinlock.h> |
|
20 21#include <asm/mach-types.h> 22 23#include "hardware.h" 24#include "soc.h" 25#include "iomap.h" 26#include "clock.h" 27#include "opp.h" 28#include "sram.h" 29 30__u32 arm_idlect1_mask; | 22 23#include <asm/mach-types.h> 24 25#include "hardware.h" 26#include "soc.h" 27#include "iomap.h" 28#include "clock.h" 29#include "opp.h" 30#include "sram.h" 31 32__u32 arm_idlect1_mask; |
31struct clk *api_ck_p, *ck_dpll1_p, *ck_ref_p; | 33/* provide direct internal access (not via clk API) to some clocks */ 34struct omap1_clk *api_ck_p, *ck_dpll1_p, *ck_ref_p; |
32 | 35 |
33static LIST_HEAD(clocks); 34static DEFINE_MUTEX(clocks_mutex); 35static DEFINE_SPINLOCK(clockfw_lock); | 36/* protect registeres shared among clk_enable/disable() and clk_set_rate() operations */ 37static DEFINE_SPINLOCK(arm_ckctl_lock); 38static DEFINE_SPINLOCK(arm_idlect2_lock); 39static DEFINE_SPINLOCK(mod_conf_ctrl_0_lock); 40static DEFINE_SPINLOCK(mod_conf_ctrl_1_lock); 41static DEFINE_SPINLOCK(swd_clk_div_ctrl_sel_lock); |
36 37/* 38 * Omap1 specific clock functions 39 */ 40 | 42 43/* 44 * Omap1 specific clock functions 45 */ 46 |
41unsigned long omap1_uart_recalc(struct clk *clk) | 47unsigned long omap1_uart_recalc(struct omap1_clk *clk, unsigned long p_rate) |
42{ 43 unsigned int val = __raw_readl(clk->enable_reg); 44 return val & 1 << clk->enable_bit ? 48000000 : 12000000; 45} 46 | 48{ 49 unsigned int val = __raw_readl(clk->enable_reg); 50 return val & 1 << clk->enable_bit ? 48000000 : 12000000; 51} 52 |
47unsigned long omap1_sossi_recalc(struct clk *clk) | 53unsigned long omap1_sossi_recalc(struct omap1_clk *clk, unsigned long p_rate) |
48{ 49 u32 div = omap_readl(MOD_CONF_CTRL_1); 50 51 div = (div >> 17) & 0x7; 52 div++; 53 | 54{ 55 u32 div = omap_readl(MOD_CONF_CTRL_1); 56 57 div = (div >> 17) & 0x7; 58 div++; 59 |
54 return clk->parent->rate / div; | 60 return p_rate / div; |
55} 56 | 61} 62 |
57static void omap1_clk_allow_idle(struct clk *clk) | 63static void omap1_clk_allow_idle(struct omap1_clk *clk) |
58{ 59 struct arm_idlect1_clk * iclk = (struct arm_idlect1_clk *)clk; 60 61 if (!(clk->flags & CLOCK_IDLE_CONTROL)) 62 return; 63 64 if (iclk->no_idle_count > 0 && !(--iclk->no_idle_count)) 65 arm_idlect1_mask |= 1 << iclk->idlect_shift; 66} 67 | 64{ 65 struct arm_idlect1_clk * iclk = (struct arm_idlect1_clk *)clk; 66 67 if (!(clk->flags & CLOCK_IDLE_CONTROL)) 68 return; 69 70 if (iclk->no_idle_count > 0 && !(--iclk->no_idle_count)) 71 arm_idlect1_mask |= 1 << iclk->idlect_shift; 72} 73 |
68static void omap1_clk_deny_idle(struct clk *clk) | 74static void omap1_clk_deny_idle(struct omap1_clk *clk) |
69{ 70 struct arm_idlect1_clk * iclk = (struct arm_idlect1_clk *)clk; 71 72 if (!(clk->flags & CLOCK_IDLE_CONTROL)) 73 return; 74 75 if (iclk->no_idle_count++ == 0) 76 arm_idlect1_mask &= ~(1 << iclk->idlect_shift); --- 47 unchanged lines hidden (view full) --- 124 newval |= arm_exp << CKCTL_ARMDIV_OFFSET; 125 newval |= dsp_exp << CKCTL_DSPDIV_OFFSET; 126 newval |= tc_exp << CKCTL_TCDIV_OFFSET; 127 newval |= dspmmu_exp << CKCTL_DSPMMUDIV_OFFSET; 128 129 return newval; 130} 131 | 75{ 76 struct arm_idlect1_clk * iclk = (struct arm_idlect1_clk *)clk; 77 78 if (!(clk->flags & CLOCK_IDLE_CONTROL)) 79 return; 80 81 if (iclk->no_idle_count++ == 0) 82 arm_idlect1_mask &= ~(1 << iclk->idlect_shift); --- 47 unchanged lines hidden (view full) --- 130 newval |= arm_exp << CKCTL_ARMDIV_OFFSET; 131 newval |= dsp_exp << CKCTL_DSPDIV_OFFSET; 132 newval |= tc_exp << CKCTL_TCDIV_OFFSET; 133 newval |= dspmmu_exp << CKCTL_DSPMMUDIV_OFFSET; 134 135 return newval; 136} 137 |
132static int calc_dsor_exp(struct clk *clk, unsigned long rate) | 138static int calc_dsor_exp(unsigned long rate, unsigned long realrate) |
133{ 134 /* Note: If target frequency is too low, this function will return 4, 135 * which is invalid value. Caller must check for this value and act 136 * accordingly. 137 * 138 * Note: This function does not check for following limitations set 139 * by the hardware (all conditions must be true): 140 * DSPMMU_CK == DSP_CK or DSPMMU_CK == DSP_CK/2 141 * ARM_CK >= TC_CK 142 * DSP_CK >= TC_CK 143 * DSPMMU_CK >= TC_CK 144 */ | 139{ 140 /* Note: If target frequency is too low, this function will return 4, 141 * which is invalid value. Caller must check for this value and act 142 * accordingly. 143 * 144 * Note: This function does not check for following limitations set 145 * by the hardware (all conditions must be true): 146 * DSPMMU_CK == DSP_CK or DSPMMU_CK == DSP_CK/2 147 * ARM_CK >= TC_CK 148 * DSP_CK >= TC_CK 149 * DSPMMU_CK >= TC_CK 150 */ |
145 unsigned long realrate; 146 struct clk * parent; | |
147 unsigned dsor_exp; 148 | 151 unsigned dsor_exp; 152 |
149 parent = clk->parent; 150 if (unlikely(parent == NULL)) | 153 if (unlikely(realrate == 0)) |
151 return -EIO; 152 | 154 return -EIO; 155 |
153 realrate = parent->rate; | |
154 for (dsor_exp=0; dsor_exp<4; dsor_exp++) { 155 if (realrate <= rate) 156 break; 157 158 realrate /= 2; 159 } 160 161 return dsor_exp; 162} 163 | 156 for (dsor_exp=0; dsor_exp<4; dsor_exp++) { 157 if (realrate <= rate) 158 break; 159 160 realrate /= 2; 161 } 162 163 return dsor_exp; 164} 165 |
164unsigned long omap1_ckctl_recalc(struct clk *clk) | 166unsigned long omap1_ckctl_recalc(struct omap1_clk *clk, unsigned long p_rate) |
165{ 166 /* Calculate divisor encoded as 2-bit exponent */ 167 int dsor = 1 << (3 & (omap_readw(ARM_CKCTL) >> clk->rate_offset)); 168 | 167{ 168 /* Calculate divisor encoded as 2-bit exponent */ 169 int dsor = 1 << (3 & (omap_readw(ARM_CKCTL) >> clk->rate_offset)); 170 |
169 return clk->parent->rate / dsor; | 171 /* update locally maintained rate, required by arm_ck for omap1_show_rates() */ 172 clk->rate = p_rate / dsor; 173 return clk->rate; |
170} 171 | 174} 175 |
172unsigned long omap1_ckctl_recalc_dsp_domain(struct clk *clk) | 176static int omap1_clk_is_enabled(struct clk_hw *hw) |
173{ | 177{ |
178 struct omap1_clk *clk = to_omap1_clk(hw); 179 bool api_ck_was_enabled = true; 180 __u32 regval32; 181 int ret; 182 183 if (!clk->ops) /* no gate -- always enabled */ 184 return 1; 185 186 if (clk->ops == &clkops_dspck) { 187 api_ck_was_enabled = omap1_clk_is_enabled(&api_ck_p->hw); 188 if (!api_ck_was_enabled) 189 if (api_ck_p->ops->enable(api_ck_p) < 0) 190 return 0; 191 } 192 193 if (clk->flags & ENABLE_REG_32BIT) 194 regval32 = __raw_readl(clk->enable_reg); 195 else 196 regval32 = __raw_readw(clk->enable_reg); 197 198 ret = regval32 & (1 << clk->enable_bit); 199 200 if (!api_ck_was_enabled) 201 api_ck_p->ops->disable(api_ck_p); 202 203 return ret; 204} 205 206 207unsigned long omap1_ckctl_recalc_dsp_domain(struct omap1_clk *clk, unsigned long p_rate) 208{ 209 bool api_ck_was_enabled; |
|
174 int dsor; 175 176 /* Calculate divisor encoded as 2-bit exponent 177 * 178 * The clock control bits are in DSP domain, 179 * so api_ck is needed for access. 180 * Note that DSP_CKCTL virt addr = phys addr, so 181 * we must use __raw_readw() instead of omap_readw(). 182 */ | 210 int dsor; 211 212 /* Calculate divisor encoded as 2-bit exponent 213 * 214 * The clock control bits are in DSP domain, 215 * so api_ck is needed for access. 216 * Note that DSP_CKCTL virt addr = phys addr, so 217 * we must use __raw_readw() instead of omap_readw(). 218 */ |
183 omap1_clk_enable(api_ck_p); | 219 api_ck_was_enabled = omap1_clk_is_enabled(&api_ck_p->hw); 220 if (!api_ck_was_enabled) 221 api_ck_p->ops->enable(api_ck_p); |
184 dsor = 1 << (3 & (__raw_readw(DSP_CKCTL) >> clk->rate_offset)); | 222 dsor = 1 << (3 & (__raw_readw(DSP_CKCTL) >> clk->rate_offset)); |
185 omap1_clk_disable(api_ck_p); | 223 if (!api_ck_was_enabled) 224 api_ck_p->ops->disable(api_ck_p); |
186 | 225 |
187 return clk->parent->rate / dsor; | 226 return p_rate / dsor; |
188} 189 190/* MPU virtual clock functions */ | 227} 228 229/* MPU virtual clock functions */ |
191int omap1_select_table_rate(struct clk *clk, unsigned long rate) | 230int omap1_select_table_rate(struct omap1_clk *clk, unsigned long rate, unsigned long p_rate) |
192{ 193 /* Find the highest supported frequency <= rate and switch to it */ 194 struct mpu_rate * ptr; 195 unsigned long ref_rate; 196 197 ref_rate = ck_ref_p->rate; 198 199 for (ptr = omap1_rate_table; ptr->rate; ptr++) { --- 18 unchanged lines hidden (view full) --- 218 omap_sram_reprogram_clock(ptr->dpllctl_val, ptr->ckctl_val); 219 220 /* XXX Do we need to recalculate the tree below DPLL1 at this point? */ 221 ck_dpll1_p->rate = ptr->pll_rate; 222 223 return 0; 224} 225 | 231{ 232 /* Find the highest supported frequency <= rate and switch to it */ 233 struct mpu_rate * ptr; 234 unsigned long ref_rate; 235 236 ref_rate = ck_ref_p->rate; 237 238 for (ptr = omap1_rate_table; ptr->rate; ptr++) { --- 18 unchanged lines hidden (view full) --- 257 omap_sram_reprogram_clock(ptr->dpllctl_val, ptr->ckctl_val); 258 259 /* XXX Do we need to recalculate the tree below DPLL1 at this point? */ 260 ck_dpll1_p->rate = ptr->pll_rate; 261 262 return 0; 263} 264 |
226int omap1_clk_set_rate_dsp_domain(struct clk *clk, unsigned long rate) | 265int omap1_clk_set_rate_dsp_domain(struct omap1_clk *clk, unsigned long rate, unsigned long p_rate) |
227{ 228 int dsor_exp; 229 u16 regval; 230 | 266{ 267 int dsor_exp; 268 u16 regval; 269 |
231 dsor_exp = calc_dsor_exp(clk, rate); | 270 dsor_exp = calc_dsor_exp(rate, p_rate); |
232 if (dsor_exp > 3) 233 dsor_exp = -EINVAL; 234 if (dsor_exp < 0) 235 return dsor_exp; 236 237 regval = __raw_readw(DSP_CKCTL); 238 regval &= ~(3 << clk->rate_offset); 239 regval |= dsor_exp << clk->rate_offset; 240 __raw_writew(regval, DSP_CKCTL); | 271 if (dsor_exp > 3) 272 dsor_exp = -EINVAL; 273 if (dsor_exp < 0) 274 return dsor_exp; 275 276 regval = __raw_readw(DSP_CKCTL); 277 regval &= ~(3 << clk->rate_offset); 278 regval |= dsor_exp << clk->rate_offset; 279 __raw_writew(regval, DSP_CKCTL); |
241 clk->rate = clk->parent->rate / (1 << dsor_exp); | 280 clk->rate = p_rate / (1 << dsor_exp); |
242 243 return 0; 244} 245 | 281 282 return 0; 283} 284 |
246long omap1_clk_round_rate_ckctl_arm(struct clk *clk, unsigned long rate) | 285long omap1_clk_round_rate_ckctl_arm(struct omap1_clk *clk, unsigned long rate, 286 unsigned long *p_rate) |
247{ | 287{ |
248 int dsor_exp = calc_dsor_exp(clk, rate); | 288 int dsor_exp = calc_dsor_exp(rate, *p_rate); 289 |
249 if (dsor_exp < 0) 250 return dsor_exp; 251 if (dsor_exp > 3) 252 dsor_exp = 3; | 290 if (dsor_exp < 0) 291 return dsor_exp; 292 if (dsor_exp > 3) 293 dsor_exp = 3; |
253 return clk->parent->rate / (1 << dsor_exp); | 294 return *p_rate / (1 << dsor_exp); |
254} 255 | 295} 296 |
256int omap1_clk_set_rate_ckctl_arm(struct clk *clk, unsigned long rate) | 297int omap1_clk_set_rate_ckctl_arm(struct omap1_clk *clk, unsigned long rate, unsigned long p_rate) |
257{ | 298{ |
299 unsigned long flags; |
|
258 int dsor_exp; 259 u16 regval; 260 | 300 int dsor_exp; 301 u16 regval; 302 |
261 dsor_exp = calc_dsor_exp(clk, rate); | 303 dsor_exp = calc_dsor_exp(rate, p_rate); |
262 if (dsor_exp > 3) 263 dsor_exp = -EINVAL; 264 if (dsor_exp < 0) 265 return dsor_exp; 266 | 304 if (dsor_exp > 3) 305 dsor_exp = -EINVAL; 306 if (dsor_exp < 0) 307 return dsor_exp; 308 |
309 /* protect ARM_CKCTL register from concurrent access via clk_enable/disable() */ 310 spin_lock_irqsave(&arm_ckctl_lock, flags); 311 |
|
267 regval = omap_readw(ARM_CKCTL); 268 regval &= ~(3 << clk->rate_offset); 269 regval |= dsor_exp << clk->rate_offset; 270 regval = verify_ckctl_value(regval); 271 omap_writew(regval, ARM_CKCTL); | 312 regval = omap_readw(ARM_CKCTL); 313 regval &= ~(3 << clk->rate_offset); 314 regval |= dsor_exp << clk->rate_offset; 315 regval = verify_ckctl_value(regval); 316 omap_writew(regval, ARM_CKCTL); |
272 clk->rate = clk->parent->rate / (1 << dsor_exp); | 317 clk->rate = p_rate / (1 << dsor_exp); 318 319 spin_unlock_irqrestore(&arm_ckctl_lock, flags); 320 |
273 return 0; 274} 275 | 321 return 0; 322} 323 |
276long omap1_round_to_table_rate(struct clk *clk, unsigned long rate) | 324long omap1_round_to_table_rate(struct omap1_clk *clk, unsigned long rate, unsigned long *p_rate) |
277{ 278 /* Find the highest supported frequency <= rate */ 279 struct mpu_rate * ptr; 280 long highest_rate; 281 unsigned long ref_rate; 282 283 ref_rate = ck_ref_p->rate; 284 --- 34 unchanged lines hidden (view full) --- 319 continue; 320 if (rate >= 96000000 / dsor) 321 break; 322 } 323 return dsor; 324} 325 326/* XXX Only needed on 1510 */ | 325{ 326 /* Find the highest supported frequency <= rate */ 327 struct mpu_rate * ptr; 328 long highest_rate; 329 unsigned long ref_rate; 330 331 ref_rate = ck_ref_p->rate; 332 --- 34 unchanged lines hidden (view full) --- 367 continue; 368 if (rate >= 96000000 / dsor) 369 break; 370 } 371 return dsor; 372} 373 374/* XXX Only needed on 1510 */ |
327int omap1_set_uart_rate(struct clk *clk, unsigned long rate) | 375long omap1_round_uart_rate(struct omap1_clk *clk, unsigned long rate, unsigned long *p_rate) |
328{ | 376{ |
377 return rate > 24000000 ? 48000000 : 12000000; 378} 379 380int omap1_set_uart_rate(struct omap1_clk *clk, unsigned long rate, unsigned long p_rate) 381{ 382 unsigned long flags; |
|
329 unsigned int val; 330 | 383 unsigned int val; 384 |
331 val = __raw_readl(clk->enable_reg); | |
332 if (rate == 12000000) | 385 if (rate == 12000000) |
333 val &= ~(1 << clk->enable_bit); | 386 val = 0; |
334 else if (rate == 48000000) | 387 else if (rate == 48000000) |
335 val |= (1 << clk->enable_bit); | 388 val = 1 << clk->enable_bit; |
336 else 337 return -EINVAL; | 389 else 390 return -EINVAL; |
391 392 /* protect MOD_CONF_CTRL_0 register from concurrent access via clk_enable/disable() */ 393 spin_lock_irqsave(&mod_conf_ctrl_0_lock, flags); 394 395 val |= __raw_readl(clk->enable_reg) & ~(1 << clk->enable_bit); |
|
338 __raw_writel(val, clk->enable_reg); | 396 __raw_writel(val, clk->enable_reg); |
397 398 spin_unlock_irqrestore(&mod_conf_ctrl_0_lock, flags); 399 |
|
339 clk->rate = rate; 340 341 return 0; 342} 343 344/* External clock (MCLK & BCLK) functions */ | 400 clk->rate = rate; 401 402 return 0; 403} 404 405/* External clock (MCLK & BCLK) functions */ |
345int omap1_set_ext_clk_rate(struct clk *clk, unsigned long rate) | 406int omap1_set_ext_clk_rate(struct omap1_clk *clk, unsigned long rate, unsigned long p_rate) |
346{ | 407{ |
408 unsigned long flags; |
|
347 unsigned dsor; 348 __u16 ratio_bits; 349 350 dsor = calc_ext_dsor(rate); 351 clk->rate = 96000000 / dsor; 352 if (dsor > 8) 353 ratio_bits = ((dsor - 8) / 2 + 6) << 2; 354 else 355 ratio_bits = (dsor - 2) << 2; 356 | 409 unsigned dsor; 410 __u16 ratio_bits; 411 412 dsor = calc_ext_dsor(rate); 413 clk->rate = 96000000 / dsor; 414 if (dsor > 8) 415 ratio_bits = ((dsor - 8) / 2 + 6) << 2; 416 else 417 ratio_bits = (dsor - 2) << 2; 418 |
419 /* protect SWD_CLK_DIV_CTRL_SEL register from concurrent access via clk_enable/disable() */ 420 spin_lock_irqsave(&swd_clk_div_ctrl_sel_lock, flags); 421 |
|
357 ratio_bits |= __raw_readw(clk->enable_reg) & ~0xfd; 358 __raw_writew(ratio_bits, clk->enable_reg); 359 | 422 ratio_bits |= __raw_readw(clk->enable_reg) & ~0xfd; 423 __raw_writew(ratio_bits, clk->enable_reg); 424 |
425 spin_unlock_irqrestore(&swd_clk_div_ctrl_sel_lock, flags); 426 |
|
360 return 0; 361} 362 | 427 return 0; 428} 429 |
363int omap1_set_sossi_rate(struct clk *clk, unsigned long rate) | 430static int calc_div_sossi(unsigned long rate, unsigned long p_rate) |
364{ | 431{ |
365 u32 l; | |
366 int div; | 432 int div; |
367 unsigned long p_rate; | |
368 | 433 |
369 p_rate = clk->parent->rate; | |
370 /* Round towards slower frequency */ 371 div = (p_rate + rate - 1) / rate; | 434 /* Round towards slower frequency */ 435 div = (p_rate + rate - 1) / rate; |
372 div--; | 436 437 return --div; 438} 439 440long omap1_round_sossi_rate(struct omap1_clk *clk, unsigned long rate, unsigned long *p_rate) 441{ 442 int div; 443 444 div = calc_div_sossi(rate, *p_rate); 445 if (div < 0) 446 div = 0; 447 else if (div > 7) 448 div = 7; 449 450 return *p_rate / (div + 1); 451} 452 453int omap1_set_sossi_rate(struct omap1_clk *clk, unsigned long rate, unsigned long p_rate) 454{ 455 unsigned long flags; 456 u32 l; 457 int div; 458 459 div = calc_div_sossi(rate, p_rate); |
373 if (div < 0 || div > 7) 374 return -EINVAL; 375 | 460 if (div < 0 || div > 7) 461 return -EINVAL; 462 |
463 /* protect MOD_CONF_CTRL_1 register from concurrent access via clk_enable/disable() */ 464 spin_lock_irqsave(&mod_conf_ctrl_1_lock, flags); 465 |
|
376 l = omap_readl(MOD_CONF_CTRL_1); 377 l &= ~(7 << 17); 378 l |= div << 17; 379 omap_writel(l, MOD_CONF_CTRL_1); 380 381 clk->rate = p_rate / (div + 1); 382 | 466 l = omap_readl(MOD_CONF_CTRL_1); 467 l &= ~(7 << 17); 468 l |= div << 17; 469 omap_writel(l, MOD_CONF_CTRL_1); 470 471 clk->rate = p_rate / (div + 1); 472 |
473 spin_unlock_irqrestore(&mod_conf_ctrl_1_lock, flags); 474 |
|
383 return 0; 384} 385 | 475 return 0; 476} 477 |
386long omap1_round_ext_clk_rate(struct clk *clk, unsigned long rate) | 478long omap1_round_ext_clk_rate(struct omap1_clk *clk, unsigned long rate, unsigned long *p_rate) |
387{ 388 return 96000000 / calc_ext_dsor(rate); 389} 390 | 479{ 480 return 96000000 / calc_ext_dsor(rate); 481} 482 |
391void omap1_init_ext_clk(struct clk *clk) | 483int omap1_init_ext_clk(struct omap1_clk *clk) |
392{ 393 unsigned dsor; 394 __u16 ratio_bits; 395 396 /* Determine current rate and ensure clock is based on 96MHz APLL */ 397 ratio_bits = __raw_readw(clk->enable_reg) & ~1; 398 __raw_writew(ratio_bits, clk->enable_reg); 399 400 ratio_bits = (ratio_bits & 0xfc) >> 2; 401 if (ratio_bits > 6) 402 dsor = (ratio_bits - 6) * 2 + 8; 403 else 404 dsor = ratio_bits + 2; 405 406 clk-> rate = 96000000 / dsor; | 484{ 485 unsigned dsor; 486 __u16 ratio_bits; 487 488 /* Determine current rate and ensure clock is based on 96MHz APLL */ 489 ratio_bits = __raw_readw(clk->enable_reg) & ~1; 490 __raw_writew(ratio_bits, clk->enable_reg); 491 492 ratio_bits = (ratio_bits & 0xfc) >> 2; 493 if (ratio_bits > 6) 494 dsor = (ratio_bits - 6) * 2 + 8; 495 else 496 dsor = ratio_bits + 2; 497 498 clk-> rate = 96000000 / dsor; |
499 500 return 0; |
|
407} 408 | 501} 502 |
409int omap1_clk_enable(struct clk *clk) | 503static int omap1_clk_enable(struct clk_hw *hw) |
410{ | 504{ |
505 struct omap1_clk *clk = to_omap1_clk(hw), *parent = to_omap1_clk(clk_hw_get_parent(hw)); |
|
411 int ret = 0; 412 | 506 int ret = 0; 507 |
413 if (clk->usecount++ == 0) { 414 if (clk->parent) { 415 ret = omap1_clk_enable(clk->parent); 416 if (ret) 417 goto err; | 508 if (parent && clk->flags & CLOCK_NO_IDLE_PARENT) 509 omap1_clk_deny_idle(parent); |
418 | 510 |
419 if (clk->flags & CLOCK_NO_IDLE_PARENT) 420 omap1_clk_deny_idle(clk->parent); 421 } 422 | 511 if (clk->ops && !(WARN_ON(!clk->ops->enable))) |
423 ret = clk->ops->enable(clk); | 512 ret = clk->ops->enable(clk); |
424 if (ret) { 425 if (clk->parent) 426 omap1_clk_disable(clk->parent); 427 goto err; 428 } 429 } 430 return ret; | |
431 | 513 |
432err: 433 clk->usecount--; | |
434 return ret; 435} 436 | 514 return ret; 515} 516 |
437void omap1_clk_disable(struct clk *clk) | 517static void omap1_clk_disable(struct clk_hw *hw) |
438{ | 518{ |
439 if (clk->usecount > 0 && !(--clk->usecount)) { | 519 struct omap1_clk *clk = to_omap1_clk(hw), *parent = to_omap1_clk(clk_hw_get_parent(hw)); 520 521 if (clk->ops && !(WARN_ON(!clk->ops->disable))) |
440 clk->ops->disable(clk); | 522 clk->ops->disable(clk); |
441 if (likely(clk->parent)) { 442 omap1_clk_disable(clk->parent); 443 if (clk->flags & CLOCK_NO_IDLE_PARENT) 444 omap1_clk_allow_idle(clk->parent); 445 } 446 } | 523 524 if (likely(parent) && clk->flags & CLOCK_NO_IDLE_PARENT) 525 omap1_clk_allow_idle(parent); |
447} 448 | 526} 527 |
449static int omap1_clk_enable_generic(struct clk *clk) | 528static int omap1_clk_enable_generic(struct omap1_clk *clk) |
450{ | 529{ |
530 unsigned long flags; |
|
451 __u16 regval16; 452 __u32 regval32; 453 454 if (unlikely(clk->enable_reg == NULL)) { 455 printk(KERN_ERR "clock.c: Enable for %s without enable code\n", | 531 __u16 regval16; 532 __u32 regval32; 533 534 if (unlikely(clk->enable_reg == NULL)) { 535 printk(KERN_ERR "clock.c: Enable for %s without enable code\n", |
456 clk->name); | 536 clk_hw_get_name(&clk->hw)); |
457 return -EINVAL; 458 } 459 | 537 return -EINVAL; 538 } 539 |
540 /* protect clk->enable_reg from concurrent access via clk_set_rate() */ 541 if (clk->enable_reg == OMAP1_IO_ADDRESS(ARM_CKCTL)) 542 spin_lock_irqsave(&arm_ckctl_lock, flags); 543 else if (clk->enable_reg == OMAP1_IO_ADDRESS(ARM_IDLECT2)) 544 spin_lock_irqsave(&arm_idlect2_lock, flags); 545 else if (clk->enable_reg == OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0)) 546 spin_lock_irqsave(&mod_conf_ctrl_0_lock, flags); 547 else if (clk->enable_reg == OMAP1_IO_ADDRESS(MOD_CONF_CTRL_1)) 548 spin_lock_irqsave(&mod_conf_ctrl_1_lock, flags); 549 else if (clk->enable_reg == OMAP1_IO_ADDRESS(SWD_CLK_DIV_CTRL_SEL)) 550 spin_lock_irqsave(&swd_clk_div_ctrl_sel_lock, flags); 551 |
|
460 if (clk->flags & ENABLE_REG_32BIT) { 461 regval32 = __raw_readl(clk->enable_reg); 462 regval32 |= (1 << clk->enable_bit); 463 __raw_writel(regval32, clk->enable_reg); 464 } else { 465 regval16 = __raw_readw(clk->enable_reg); 466 regval16 |= (1 << clk->enable_bit); 467 __raw_writew(regval16, clk->enable_reg); 468 } 469 | 552 if (clk->flags & ENABLE_REG_32BIT) { 553 regval32 = __raw_readl(clk->enable_reg); 554 regval32 |= (1 << clk->enable_bit); 555 __raw_writel(regval32, clk->enable_reg); 556 } else { 557 regval16 = __raw_readw(clk->enable_reg); 558 regval16 |= (1 << clk->enable_bit); 559 __raw_writew(regval16, clk->enable_reg); 560 } 561 |
562 if (clk->enable_reg == OMAP1_IO_ADDRESS(ARM_CKCTL)) 563 spin_unlock_irqrestore(&arm_ckctl_lock, flags); 564 else if (clk->enable_reg == OMAP1_IO_ADDRESS(ARM_IDLECT2)) 565 spin_unlock_irqrestore(&arm_idlect2_lock, flags); 566 else if (clk->enable_reg == OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0)) 567 spin_unlock_irqrestore(&mod_conf_ctrl_0_lock, flags); 568 else if (clk->enable_reg == OMAP1_IO_ADDRESS(MOD_CONF_CTRL_1)) 569 spin_unlock_irqrestore(&mod_conf_ctrl_1_lock, flags); 570 else if (clk->enable_reg == OMAP1_IO_ADDRESS(SWD_CLK_DIV_CTRL_SEL)) 571 spin_unlock_irqrestore(&swd_clk_div_ctrl_sel_lock, flags); 572 |
|
470 return 0; 471} 472 | 573 return 0; 574} 575 |
473static void omap1_clk_disable_generic(struct clk *clk) | 576static void omap1_clk_disable_generic(struct omap1_clk *clk) |
474{ | 577{ |
578 unsigned long flags; |
|
475 __u16 regval16; 476 __u32 regval32; 477 478 if (clk->enable_reg == NULL) 479 return; 480 | 579 __u16 regval16; 580 __u32 regval32; 581 582 if (clk->enable_reg == NULL) 583 return; 584 |
585 /* protect clk->enable_reg from concurrent access via clk_set_rate() */ 586 if (clk->enable_reg == OMAP1_IO_ADDRESS(ARM_CKCTL)) 587 spin_lock_irqsave(&arm_ckctl_lock, flags); 588 else if (clk->enable_reg == OMAP1_IO_ADDRESS(ARM_IDLECT2)) 589 spin_lock_irqsave(&arm_idlect2_lock, flags); 590 else if (clk->enable_reg == OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0)) 591 spin_lock_irqsave(&mod_conf_ctrl_0_lock, flags); 592 else if (clk->enable_reg == OMAP1_IO_ADDRESS(MOD_CONF_CTRL_1)) 593 spin_lock_irqsave(&mod_conf_ctrl_1_lock, flags); 594 else if (clk->enable_reg == OMAP1_IO_ADDRESS(SWD_CLK_DIV_CTRL_SEL)) 595 spin_lock_irqsave(&swd_clk_div_ctrl_sel_lock, flags); 596 |
|
481 if (clk->flags & ENABLE_REG_32BIT) { 482 regval32 = __raw_readl(clk->enable_reg); 483 regval32 &= ~(1 << clk->enable_bit); 484 __raw_writel(regval32, clk->enable_reg); 485 } else { 486 regval16 = __raw_readw(clk->enable_reg); 487 regval16 &= ~(1 << clk->enable_bit); 488 __raw_writew(regval16, clk->enable_reg); 489 } | 597 if (clk->flags & ENABLE_REG_32BIT) { 598 regval32 = __raw_readl(clk->enable_reg); 599 regval32 &= ~(1 << clk->enable_bit); 600 __raw_writel(regval32, clk->enable_reg); 601 } else { 602 regval16 = __raw_readw(clk->enable_reg); 603 regval16 &= ~(1 << clk->enable_bit); 604 __raw_writew(regval16, clk->enable_reg); 605 } |
606 607 if (clk->enable_reg == OMAP1_IO_ADDRESS(ARM_CKCTL)) 608 spin_unlock_irqrestore(&arm_ckctl_lock, flags); 609 else if (clk->enable_reg == OMAP1_IO_ADDRESS(ARM_IDLECT2)) 610 spin_unlock_irqrestore(&arm_idlect2_lock, flags); 611 else if (clk->enable_reg == OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0)) 612 spin_unlock_irqrestore(&mod_conf_ctrl_0_lock, flags); 613 else if (clk->enable_reg == OMAP1_IO_ADDRESS(MOD_CONF_CTRL_1)) 614 spin_unlock_irqrestore(&mod_conf_ctrl_1_lock, flags); 615 else if (clk->enable_reg == OMAP1_IO_ADDRESS(SWD_CLK_DIV_CTRL_SEL)) 616 spin_unlock_irqrestore(&swd_clk_div_ctrl_sel_lock, flags); |
|
490} 491 492const struct clkops clkops_generic = { 493 .enable = omap1_clk_enable_generic, 494 .disable = omap1_clk_disable_generic, 495}; 496 | 617} 618 619const struct clkops clkops_generic = { 620 .enable = omap1_clk_enable_generic, 621 .disable = omap1_clk_disable_generic, 622}; 623 |
497static int omap1_clk_enable_dsp_domain(struct clk *clk) | 624static int omap1_clk_enable_dsp_domain(struct omap1_clk *clk) |
498{ | 625{ |
499 int retval; | 626 bool api_ck_was_enabled; 627 int retval = 0; |
500 | 628 |
501 retval = omap1_clk_enable(api_ck_p); | 629 api_ck_was_enabled = omap1_clk_is_enabled(&api_ck_p->hw); 630 if (!api_ck_was_enabled) 631 retval = api_ck_p->ops->enable(api_ck_p); 632 |
502 if (!retval) { 503 retval = omap1_clk_enable_generic(clk); | 633 if (!retval) { 634 retval = omap1_clk_enable_generic(clk); |
504 omap1_clk_disable(api_ck_p); | 635 636 if (!api_ck_was_enabled) 637 api_ck_p->ops->disable(api_ck_p); |
505 } 506 507 return retval; 508} 509 | 638 } 639 640 return retval; 641} 642 |
510static void omap1_clk_disable_dsp_domain(struct clk *clk) | 643static void omap1_clk_disable_dsp_domain(struct omap1_clk *clk) |
511{ | 644{ |
512 if (omap1_clk_enable(api_ck_p) == 0) { 513 omap1_clk_disable_generic(clk); 514 omap1_clk_disable(api_ck_p); 515 } | 645 bool api_ck_was_enabled; 646 647 api_ck_was_enabled = omap1_clk_is_enabled(&api_ck_p->hw); 648 if (!api_ck_was_enabled) 649 if (api_ck_p->ops->enable(api_ck_p) < 0) 650 return; 651 652 omap1_clk_disable_generic(clk); 653 654 if (!api_ck_was_enabled) 655 api_ck_p->ops->disable(api_ck_p); |
516} 517 518const struct clkops clkops_dspck = { 519 .enable = omap1_clk_enable_dsp_domain, 520 .disable = omap1_clk_disable_dsp_domain, 521}; 522 523/* XXX SYSC register handling does not belong in the clock framework */ | 656} 657 658const struct clkops clkops_dspck = { 659 .enable = omap1_clk_enable_dsp_domain, 660 .disable = omap1_clk_disable_dsp_domain, 661}; 662 663/* XXX SYSC register handling does not belong in the clock framework */ |
524static int omap1_clk_enable_uart_functional_16xx(struct clk *clk) | 664static int omap1_clk_enable_uart_functional_16xx(struct omap1_clk *clk) |
525{ 526 int ret; 527 struct uart_clk *uclk; 528 529 ret = omap1_clk_enable_generic(clk); 530 if (ret == 0) { 531 /* Set smart idle acknowledgement mode */ 532 uclk = (struct uart_clk *)clk; 533 omap_writeb((omap_readb(uclk->sysc_addr) & ~0x10) | 8, 534 uclk->sysc_addr); 535 } 536 537 return ret; 538} 539 540/* XXX SYSC register handling does not belong in the clock framework */ | 665{ 666 int ret; 667 struct uart_clk *uclk; 668 669 ret = omap1_clk_enable_generic(clk); 670 if (ret == 0) { 671 /* Set smart idle acknowledgement mode */ 672 uclk = (struct uart_clk *)clk; 673 omap_writeb((omap_readb(uclk->sysc_addr) & ~0x10) | 8, 674 uclk->sysc_addr); 675 } 676 677 return ret; 678} 679 680/* XXX SYSC register handling does not belong in the clock framework */ |
541static void omap1_clk_disable_uart_functional_16xx(struct clk *clk) | 681static void omap1_clk_disable_uart_functional_16xx(struct omap1_clk *clk) |
542{ 543 struct uart_clk *uclk; 544 545 /* Set force idle acknowledgement mode */ 546 uclk = (struct uart_clk *)clk; 547 omap_writeb((omap_readb(uclk->sysc_addr) & ~0x18), uclk->sysc_addr); 548 549 omap1_clk_disable_generic(clk); 550} 551 552/* XXX SYSC register handling does not belong in the clock framework */ 553const struct clkops clkops_uart_16xx = { 554 .enable = omap1_clk_enable_uart_functional_16xx, 555 .disable = omap1_clk_disable_uart_functional_16xx, 556}; 557 | 682{ 683 struct uart_clk *uclk; 684 685 /* Set force idle acknowledgement mode */ 686 uclk = (struct uart_clk *)clk; 687 omap_writeb((omap_readb(uclk->sysc_addr) & ~0x18), uclk->sysc_addr); 688 689 omap1_clk_disable_generic(clk); 690} 691 692/* XXX SYSC register handling does not belong in the clock framework */ 693const struct clkops clkops_uart_16xx = { 694 .enable = omap1_clk_enable_uart_functional_16xx, 695 .disable = omap1_clk_disable_uart_functional_16xx, 696}; 697 |
558long omap1_clk_round_rate(struct clk *clk, unsigned long rate) | 698static unsigned long omap1_clk_recalc_rate(struct clk_hw *hw, unsigned long p_rate) |
559{ | 699{ |
560 if (clk->round_rate != NULL) 561 return clk->round_rate(clk, rate); | 700 struct omap1_clk *clk = to_omap1_clk(hw); |
562 | 701 |
702 if (clk->recalc) 703 return clk->recalc(clk, p_rate); 704 |
|
563 return clk->rate; 564} 565 | 705 return clk->rate; 706} 707 |
566int omap1_clk_set_rate(struct clk *clk, unsigned long rate) | 708static long omap1_clk_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *p_rate) |
567{ | 709{ |
710 struct omap1_clk *clk = to_omap1_clk(hw); 711 712 if (clk->round_rate != NULL) 713 return clk->round_rate(clk, rate, p_rate); 714 715 return omap1_clk_recalc_rate(hw, *p_rate); 716} 717 718static int omap1_clk_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long p_rate) 719{ 720 struct omap1_clk *clk = to_omap1_clk(hw); |
|
568 int ret = -EINVAL; 569 570 if (clk->set_rate) | 721 int ret = -EINVAL; 722 723 if (clk->set_rate) |
571 ret = clk->set_rate(clk, rate); | 724 ret = clk->set_rate(clk, rate, p_rate); |
572 return ret; 573} 574 575/* 576 * Omap1 clock reset and init functions 577 */ 578 | 725 return ret; 726} 727 728/* 729 * Omap1 clock reset and init functions 730 */ 731 |
732static int omap1_clk_init_op(struct clk_hw *hw) 733{ 734 struct omap1_clk *clk = to_omap1_clk(hw); 735 736 if (clk->init) 737 return clk->init(clk); 738 739 return 0; 740} 741 |
|
579#ifdef CONFIG_OMAP_RESET_CLOCKS 580 | 742#ifdef CONFIG_OMAP_RESET_CLOCKS 743 |
581void omap1_clk_disable_unused(struct clk *clk) | 744static void omap1_clk_disable_unused(struct clk_hw *hw) |
582{ | 745{ |
583 __u32 regval32; | 746 struct omap1_clk *clk = to_omap1_clk(hw); 747 const char *name = clk_hw_get_name(hw); |
584 585 /* Clocks in the DSP domain need api_ck. Just assume bootloader 586 * has not enabled any DSP clocks */ 587 if (clk->enable_reg == DSP_IDLECT2) { | 748 749 /* Clocks in the DSP domain need api_ck. Just assume bootloader 750 * has not enabled any DSP clocks */ 751 if (clk->enable_reg == DSP_IDLECT2) { |
588 pr_info("Skipping reset check for DSP domain clock \"%s\"\n", 589 clk->name); | 752 pr_info("Skipping reset check for DSP domain clock \"%s\"\n", name); |
590 return; 591 } 592 | 753 return; 754 } 755 |
593 /* Is the clock already disabled? */ 594 if (clk->flags & ENABLE_REG_32BIT) 595 regval32 = __raw_readl(clk->enable_reg); 596 else 597 regval32 = __raw_readw(clk->enable_reg); 598 599 if ((regval32 & (1 << clk->enable_bit)) == 0) 600 return; 601 602 printk(KERN_INFO "Disabling unused clock \"%s\"... ", clk->name); 603 clk->ops->disable(clk); | 756 pr_info("Disabling unused clock \"%s\"... ", name); 757 omap1_clk_disable(hw); |
604 printk(" done\n"); 605} 606 607#endif 608 | 758 printk(" done\n"); 759} 760 761#endif 762 |
763const struct clk_ops omap1_clk_gate_ops = { 764 .enable = omap1_clk_enable, 765 .disable = omap1_clk_disable, 766 .is_enabled = omap1_clk_is_enabled, 767#ifdef CONFIG_OMAP_RESET_CLOCKS 768 .disable_unused = omap1_clk_disable_unused, 769#endif 770}; |
|
609 | 771 |
610int clk_enable(struct clk *clk) 611{ 612 unsigned long flags; 613 int ret; | 772const struct clk_ops omap1_clk_rate_ops = { 773 .recalc_rate = omap1_clk_recalc_rate, 774 .round_rate = omap1_clk_round_rate, 775 .set_rate = omap1_clk_set_rate, 776 .init = omap1_clk_init_op, 777}; |
614 | 778 |
615 if (IS_ERR_OR_NULL(clk)) 616 return -EINVAL; | 779const struct clk_ops omap1_clk_full_ops = { 780 .enable = omap1_clk_enable, 781 .disable = omap1_clk_disable, 782 .is_enabled = omap1_clk_is_enabled, 783#ifdef CONFIG_OMAP_RESET_CLOCKS 784 .disable_unused = omap1_clk_disable_unused, 785#endif 786 .recalc_rate = omap1_clk_recalc_rate, 787 .round_rate = omap1_clk_round_rate, 788 .set_rate = omap1_clk_set_rate, 789 .init = omap1_clk_init_op, 790}; |
617 | 791 |
618 spin_lock_irqsave(&clockfw_lock, flags); 619 ret = omap1_clk_enable(clk); 620 spin_unlock_irqrestore(&clockfw_lock, flags); 621 622 return ret; 623} 624EXPORT_SYMBOL(clk_enable); 625 626void clk_disable(struct clk *clk) 627{ 628 unsigned long flags; 629 630 if (IS_ERR_OR_NULL(clk)) 631 return; 632 633 spin_lock_irqsave(&clockfw_lock, flags); 634 if (clk->usecount == 0) { 635 pr_err("Trying disable clock %s with 0 usecount\n", 636 clk->name); 637 WARN_ON(1); 638 goto out; 639 } 640 641 omap1_clk_disable(clk); 642 643out: 644 spin_unlock_irqrestore(&clockfw_lock, flags); 645} 646EXPORT_SYMBOL(clk_disable); 647 648unsigned long clk_get_rate(struct clk *clk) 649{ 650 unsigned long flags; 651 unsigned long ret; 652 653 if (IS_ERR_OR_NULL(clk)) 654 return 0; 655 656 spin_lock_irqsave(&clockfw_lock, flags); 657 ret = clk->rate; 658 spin_unlock_irqrestore(&clockfw_lock, flags); 659 660 return ret; 661} 662EXPORT_SYMBOL(clk_get_rate); 663 | |
664/* | 792/* |
665 * Optional clock functions defined in include/linux/clk.h 666 */ 667 668long clk_round_rate(struct clk *clk, unsigned long rate) 669{ 670 unsigned long flags; 671 long ret; 672 673 if (IS_ERR_OR_NULL(clk)) 674 return 0; 675 676 spin_lock_irqsave(&clockfw_lock, flags); 677 ret = omap1_clk_round_rate(clk, rate); 678 spin_unlock_irqrestore(&clockfw_lock, flags); 679 680 return ret; 681} 682EXPORT_SYMBOL(clk_round_rate); 683 684int clk_set_rate(struct clk *clk, unsigned long rate) 685{ 686 unsigned long flags; 687 int ret = -EINVAL; 688 689 if (IS_ERR_OR_NULL(clk)) 690 return ret; 691 692 spin_lock_irqsave(&clockfw_lock, flags); 693 ret = omap1_clk_set_rate(clk, rate); 694 if (ret == 0) 695 propagate_rate(clk); 696 spin_unlock_irqrestore(&clockfw_lock, flags); 697 698 return ret; 699} 700EXPORT_SYMBOL(clk_set_rate); 701 702int clk_set_parent(struct clk *clk, struct clk *parent) 703{ 704 WARN_ONCE(1, "clk_set_parent() not implemented for OMAP1\n"); 705 706 return -EINVAL; 707} 708EXPORT_SYMBOL(clk_set_parent); 709 710struct clk *clk_get_parent(struct clk *clk) 711{ 712 return clk->parent; 713} 714EXPORT_SYMBOL(clk_get_parent); 715 716/* | |
717 * OMAP specific clock functions shared between omap1 and omap2 718 */ 719 720/* Used for clocks that always have same value as the parent clock */ | 793 * OMAP specific clock functions shared between omap1 and omap2 794 */ 795 796/* Used for clocks that always have same value as the parent clock */ |
721unsigned long followparent_recalc(struct clk *clk) | 797unsigned long followparent_recalc(struct omap1_clk *clk, unsigned long p_rate) |
722{ | 798{ |
723 return clk->parent->rate; | 799 return p_rate; |
724} 725 726/* 727 * Used for clocks that have the same value as the parent clock, 728 * divided by some factor 729 */ | 800} 801 802/* 803 * Used for clocks that have the same value as the parent clock, 804 * divided by some factor 805 */ |
730unsigned long omap_fixed_divisor_recalc(struct clk *clk) | 806unsigned long omap_fixed_divisor_recalc(struct omap1_clk *clk, unsigned long p_rate) |
731{ 732 WARN_ON(!clk->fixed_div); 733 | 807{ 808 WARN_ON(!clk->fixed_div); 809 |
734 return clk->parent->rate / clk->fixed_div; | 810 return p_rate / clk->fixed_div; |
735} 736 737/* Propagate rate to children */ | 811} 812 813/* Propagate rate to children */ |
738void propagate_rate(struct clk *tclk) | 814void propagate_rate(struct omap1_clk *tclk) |
739{ 740 struct clk *clkp; 741 | 815{ 816 struct clk *clkp; 817 |
742 list_for_each_entry(clkp, &tclk->children, sibling) { 743 if (clkp->recalc) 744 clkp->rate = clkp->recalc(clkp); 745 propagate_rate(clkp); 746 } 747} | 818 /* depend on CCF ability to recalculate new rates across whole clock subtree */ 819 if (WARN_ON(!(clk_hw_get_flags(&tclk->hw) & CLK_GET_RATE_NOCACHE))) 820 return; |
748 | 821 |
749static LIST_HEAD(root_clks); 750 751/** 752 * clk_preinit - initialize any fields in the struct clk before clk init 753 * @clk: struct clk * to initialize 754 * 755 * Initialize any struct clk fields needed before normal clk initialization 756 * can run. No return value. 757 */ 758void clk_preinit(struct clk *clk) 759{ 760 INIT_LIST_HEAD(&clk->children); 761} 762 763int clk_register(struct clk *clk) 764{ 765 if (IS_ERR_OR_NULL(clk)) 766 return -EINVAL; 767 768 /* 769 * trap out already registered clocks 770 */ 771 if (clk->node.next || clk->node.prev) 772 return 0; 773 774 mutex_lock(&clocks_mutex); 775 if (clk->parent) 776 list_add(&clk->sibling, &clk->parent->children); 777 else 778 list_add(&clk->sibling, &root_clks); 779 780 list_add(&clk->node, &clocks); 781 if (clk->init) 782 clk->init(clk); 783 mutex_unlock(&clocks_mutex); 784 785 return 0; 786} 787EXPORT_SYMBOL(clk_register); 788 789void clk_unregister(struct clk *clk) 790{ 791 if (IS_ERR_OR_NULL(clk)) | 822 clkp = clk_get_sys(NULL, clk_hw_get_name(&tclk->hw)); 823 if (WARN_ON(!clkp)) |
792 return; 793 | 824 return; 825 |
794 mutex_lock(&clocks_mutex); 795 list_del(&clk->sibling); 796 list_del(&clk->node); 797 mutex_unlock(&clocks_mutex); | 826 clk_get_rate(clkp); 827 clk_put(clkp); |
798} | 828} |
799EXPORT_SYMBOL(clk_unregister); | |
800 | 829 |
801/* 802 * Low level helpers 803 */ 804static int clkll_enable_null(struct clk *clk) 805{ 806 return 0; 807} 808 809static void clkll_disable_null(struct clk *clk) 810{ 811} 812 813const struct clkops clkops_null = { 814 .enable = clkll_enable_null, 815 .disable = clkll_disable_null, | 830const struct clk_ops omap1_clk_null_ops = { |
816}; 817 818/* 819 * Dummy clock 820 * 821 * Used for clock aliases that are needed on some OMAPs, but not others 822 */ | 831}; 832 833/* 834 * Dummy clock 835 * 836 * Used for clock aliases that are needed on some OMAPs, but not others 837 */ |
823struct clk dummy_ck = { 824 .name = "dummy", 825 .ops = &clkops_null, | 838struct omap1_clk dummy_ck __refdata = { 839 .hw.init = CLK_HW_INIT_NO_PARENT("dummy", &omap1_clk_null_ops, 0), |
826}; | 840}; |
827 828/* 829 * 830 */ 831 832#ifdef CONFIG_OMAP_RESET_CLOCKS 833/* 834 * Disable any unused clocks left on by the bootloader 835 */ 836static int __init clk_disable_unused(void) 837{ 838 struct clk *ck; 839 unsigned long flags; 840 841 pr_info("clock: disabling unused clocks to save power\n"); 842 843 spin_lock_irqsave(&clockfw_lock, flags); 844 list_for_each_entry(ck, &clocks, node) { 845 if (ck->ops == &clkops_null) 846 continue; 847 848 if (ck->usecount > 0 || !ck->enable_reg) 849 continue; 850 851 omap1_clk_disable_unused(ck); 852 } 853 spin_unlock_irqrestore(&clockfw_lock, flags); 854 855 return 0; 856} 857late_initcall(clk_disable_unused); 858#endif 859 860#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS) 861/* 862 * debugfs support to trace clock tree hierarchy and attributes 863 */ 864 865#include <linux/debugfs.h> 866#include <linux/seq_file.h> 867 868static struct dentry *clk_debugfs_root; 869 870static int debug_clock_show(struct seq_file *s, void *unused) 871{ 872 struct clk *c; 873 struct clk *pa; 874 875 mutex_lock(&clocks_mutex); 876 seq_printf(s, "%-30s %-30s %-10s %s\n", 877 "clock-name", "parent-name", "rate", "use-count"); 878 879 list_for_each_entry(c, &clocks, node) { 880 pa = c->parent; 881 seq_printf(s, "%-30s %-30s %-10lu %d\n", 882 c->name, pa ? pa->name : "none", c->rate, 883 c->usecount); 884 } 885 mutex_unlock(&clocks_mutex); 886 887 return 0; 888} 889 890DEFINE_SHOW_ATTRIBUTE(debug_clock); 891 892static void clk_debugfs_register_one(struct clk *c) 893{ 894 struct dentry *d; 895 struct clk *pa = c->parent; 896 897 d = debugfs_create_dir(c->name, pa ? pa->dent : clk_debugfs_root); 898 c->dent = d; 899 900 debugfs_create_u8("usecount", S_IRUGO, c->dent, &c->usecount); 901 debugfs_create_ulong("rate", S_IRUGO, c->dent, &c->rate); 902 debugfs_create_x8("flags", S_IRUGO, c->dent, &c->flags); 903} 904 905static void clk_debugfs_register(struct clk *c) 906{ 907 struct clk *pa = c->parent; 908 909 if (pa && !pa->dent) 910 clk_debugfs_register(pa); 911 912 if (!c->dent) 913 clk_debugfs_register_one(c); 914} 915 916static int __init clk_debugfs_init(void) 917{ 918 struct clk *c; 919 struct dentry *d; 920 921 d = debugfs_create_dir("clock", NULL); 922 clk_debugfs_root = d; 923 924 list_for_each_entry(c, &clocks, node) 925 clk_debugfs_register(c); 926 927 debugfs_create_file("summary", S_IRUGO, d, NULL, &debug_clock_fops); 928 929 return 0; 930} 931late_initcall(clk_debugfs_init); 932 933#endif /* defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS) */ | |