Commit | Line | Data |
---|---|---|
3179a019 TL |
1 | /* |
2 | * linux/arch/arm/mach-omap1/clock.c | |
3 | * | |
51c19541 | 4 | * Copyright (C) 2004 - 2005, 2009-2010 Nokia Corporation |
3179a019 TL |
5 | * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> |
6 | * | |
7 | * Modified to use omap shared clock framework by | |
8 | * Tony Lindgren <tony@atomide.com> | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or modify | |
11 | * it under the terms of the GNU General Public License version 2 as | |
12 | * published by the Free Software Foundation. | |
13 | */ | |
14 | #include <linux/module.h> | |
15 | #include <linux/kernel.h> | |
16 | #include <linux/list.h> | |
17 | #include <linux/errno.h> | |
18 | #include <linux/err.h> | |
f8ce2547 | 19 | #include <linux/clk.h> |
fced80c7 | 20 | #include <linux/io.h> |
3179a019 | 21 | |
90afd5cb | 22 | #include <asm/mach-types.h> |
d7e8f1f9 | 23 | #include <asm/clkdev.h> |
3179a019 | 24 | |
ce491cf8 TL |
25 | #include <plat/cpu.h> |
26 | #include <plat/usb.h> | |
27 | #include <plat/clock.h> | |
28 | #include <plat/sram.h> | |
52650505 | 29 | #include <plat/clkdev_omap.h> |
548d8495 | 30 | |
3179a019 | 31 | #include "clock.h" |
52650505 PW |
32 | #include "opp.h" |
33 | ||
34 | __u32 arm_idlect1_mask; | |
35 | struct clk *api_ck_p, *ck_dpll1_p, *ck_ref_p; | |
36 | ||
37 | /*------------------------------------------------------------------------- | |
38 | * Omap1 specific clock functions | |
39 | *-------------------------------------------------------------------------*/ | |
3179a019 | 40 | |
f1c25437 RK |
41 | static int clk_omap1_dummy_enable(struct clk *clk) |
42 | { | |
43 | return 0; | |
44 | } | |
45 | ||
46 | static void clk_omap1_dummy_disable(struct clk *clk) | |
47 | { | |
48 | } | |
49 | ||
52650505 PW |
50 | const struct clkops clkops_dummy = { |
51 | .enable = clk_omap1_dummy_enable, | |
52 | .disable = clk_omap1_dummy_disable, | |
d7e8f1f9 RK |
53 | }; |
54 | ||
52650505 | 55 | unsigned long omap1_uart_recalc(struct clk *clk) |
3179a019 | 56 | { |
fed415e4 | 57 | unsigned int val = __raw_readl(clk->enable_reg); |
8b9dbc16 | 58 | return val & clk->enable_bit ? 48000000 : 12000000; |
3179a019 TL |
59 | } |
60 | ||
52650505 | 61 | unsigned long omap1_sossi_recalc(struct clk *clk) |
df2c2e70 ID |
62 | { |
63 | u32 div = omap_readl(MOD_CONF_CTRL_1); | |
64 | ||
65 | div = (div >> 17) & 0x7; | |
66 | div++; | |
8b9dbc16 RK |
67 | |
68 | return clk->parent->rate / div; | |
df2c2e70 ID |
69 | } |
70 | ||
3179a019 TL |
71 | static void omap1_clk_allow_idle(struct clk *clk) |
72 | { | |
73 | struct arm_idlect1_clk * iclk = (struct arm_idlect1_clk *)clk; | |
74 | ||
75 | if (!(clk->flags & CLOCK_IDLE_CONTROL)) | |
76 | return; | |
77 | ||
78 | if (iclk->no_idle_count > 0 && !(--iclk->no_idle_count)) | |
79 | arm_idlect1_mask |= 1 << iclk->idlect_shift; | |
80 | } | |
81 | ||
82 | static void omap1_clk_deny_idle(struct clk *clk) | |
83 | { | |
84 | struct arm_idlect1_clk * iclk = (struct arm_idlect1_clk *)clk; | |
85 | ||
86 | if (!(clk->flags & CLOCK_IDLE_CONTROL)) | |
87 | return; | |
88 | ||
89 | if (iclk->no_idle_count++ == 0) | |
90 | arm_idlect1_mask &= ~(1 << iclk->idlect_shift); | |
91 | } | |
92 | ||
93 | static __u16 verify_ckctl_value(__u16 newval) | |
94 | { | |
95 | /* This function checks for following limitations set | |
96 | * by the hardware (all conditions must be true): | |
97 | * DSPMMU_CK == DSP_CK or DSPMMU_CK == DSP_CK/2 | |
98 | * ARM_CK >= TC_CK | |
99 | * DSP_CK >= TC_CK | |
100 | * DSPMMU_CK >= TC_CK | |
101 | * | |
102 | * In addition following rules are enforced: | |
103 | * LCD_CK <= TC_CK | |
104 | * ARMPER_CK <= TC_CK | |
105 | * | |
106 | * However, maximum frequencies are not checked for! | |
107 | */ | |
108 | __u8 per_exp; | |
109 | __u8 lcd_exp; | |
110 | __u8 arm_exp; | |
111 | __u8 dsp_exp; | |
112 | __u8 tc_exp; | |
113 | __u8 dspmmu_exp; | |
114 | ||
115 | per_exp = (newval >> CKCTL_PERDIV_OFFSET) & 3; | |
116 | lcd_exp = (newval >> CKCTL_LCDDIV_OFFSET) & 3; | |
117 | arm_exp = (newval >> CKCTL_ARMDIV_OFFSET) & 3; | |
118 | dsp_exp = (newval >> CKCTL_DSPDIV_OFFSET) & 3; | |
119 | tc_exp = (newval >> CKCTL_TCDIV_OFFSET) & 3; | |
120 | dspmmu_exp = (newval >> CKCTL_DSPMMUDIV_OFFSET) & 3; | |
121 | ||
122 | if (dspmmu_exp < dsp_exp) | |
123 | dspmmu_exp = dsp_exp; | |
124 | if (dspmmu_exp > dsp_exp+1) | |
125 | dspmmu_exp = dsp_exp+1; | |
126 | if (tc_exp < arm_exp) | |
127 | tc_exp = arm_exp; | |
128 | if (tc_exp < dspmmu_exp) | |
129 | tc_exp = dspmmu_exp; | |
130 | if (tc_exp > lcd_exp) | |
131 | lcd_exp = tc_exp; | |
132 | if (tc_exp > per_exp) | |
133 | per_exp = tc_exp; | |
134 | ||
135 | newval &= 0xf000; | |
136 | newval |= per_exp << CKCTL_PERDIV_OFFSET; | |
137 | newval |= lcd_exp << CKCTL_LCDDIV_OFFSET; | |
138 | newval |= arm_exp << CKCTL_ARMDIV_OFFSET; | |
139 | newval |= dsp_exp << CKCTL_DSPDIV_OFFSET; | |
140 | newval |= tc_exp << CKCTL_TCDIV_OFFSET; | |
141 | newval |= dspmmu_exp << CKCTL_DSPMMUDIV_OFFSET; | |
142 | ||
143 | return newval; | |
144 | } | |
145 | ||
146 | static int calc_dsor_exp(struct clk *clk, unsigned long rate) | |
147 | { | |
148 | /* Note: If target frequency is too low, this function will return 4, | |
149 | * which is invalid value. Caller must check for this value and act | |
150 | * accordingly. | |
151 | * | |
152 | * Note: This function does not check for following limitations set | |
153 | * by the hardware (all conditions must be true): | |
154 | * DSPMMU_CK == DSP_CK or DSPMMU_CK == DSP_CK/2 | |
155 | * ARM_CK >= TC_CK | |
156 | * DSP_CK >= TC_CK | |
157 | * DSPMMU_CK >= TC_CK | |
158 | */ | |
159 | unsigned long realrate; | |
160 | struct clk * parent; | |
161 | unsigned dsor_exp; | |
162 | ||
3179a019 | 163 | parent = clk->parent; |
c0fc18c5 | 164 | if (unlikely(parent == NULL)) |
3179a019 TL |
165 | return -EIO; |
166 | ||
167 | realrate = parent->rate; | |
168 | for (dsor_exp=0; dsor_exp<4; dsor_exp++) { | |
169 | if (realrate <= rate) | |
170 | break; | |
171 | ||
172 | realrate /= 2; | |
173 | } | |
174 | ||
175 | return dsor_exp; | |
176 | } | |
177 | ||
52650505 | 178 | unsigned long omap1_ckctl_recalc(struct clk *clk) |
3179a019 | 179 | { |
3179a019 | 180 | /* Calculate divisor encoded as 2-bit exponent */ |
8b9dbc16 | 181 | int dsor = 1 << (3 & (omap_readw(ARM_CKCTL) >> clk->rate_offset)); |
3179a019 | 182 | |
8b9dbc16 | 183 | return clk->parent->rate / dsor; |
3179a019 TL |
184 | } |
185 | ||
52650505 | 186 | unsigned long omap1_ckctl_recalc_dsp_domain(struct clk *clk) |
3179a019 TL |
187 | { |
188 | int dsor; | |
189 | ||
190 | /* Calculate divisor encoded as 2-bit exponent | |
191 | * | |
192 | * The clock control bits are in DSP domain, | |
193 | * so api_ck is needed for access. | |
194 | * Note that DSP_CKCTL virt addr = phys addr, so | |
195 | * we must use __raw_readw() instead of omap_readw(). | |
196 | */ | |
52650505 | 197 | omap1_clk_enable(api_ck_p); |
3179a019 | 198 | dsor = 1 << (3 & (__raw_readw(DSP_CKCTL) >> clk->rate_offset)); |
52650505 | 199 | omap1_clk_disable(api_ck_p); |
3179a019 | 200 | |
8b9dbc16 | 201 | return clk->parent->rate / dsor; |
3179a019 TL |
202 | } |
203 | ||
204 | /* MPU virtual clock functions */ | |
52650505 | 205 | int omap1_select_table_rate(struct clk *clk, unsigned long rate) |
3179a019 TL |
206 | { |
207 | /* Find the highest supported frequency <= rate and switch to it */ | |
208 | struct mpu_rate * ptr; | |
52650505 PW |
209 | unsigned long dpll1_rate, ref_rate; |
210 | ||
af022faf PW |
211 | dpll1_rate = ck_dpll1_p->rate; |
212 | ref_rate = ck_ref_p->rate; | |
3179a019 | 213 | |
52650505 PW |
214 | for (ptr = omap1_rate_table; ptr->rate; ptr++) { |
215 | if (ptr->xtal != ref_rate) | |
3179a019 TL |
216 | continue; |
217 | ||
218 | /* DPLL1 cannot be reprogrammed without risking system crash */ | |
52650505 | 219 | if (likely(dpll1_rate != 0) && ptr->pll_rate != dpll1_rate) |
3179a019 TL |
220 | continue; |
221 | ||
222 | /* Can check only after xtal frequency check */ | |
223 | if (ptr->rate <= rate) | |
224 | break; | |
225 | } | |
226 | ||
227 | if (!ptr->rate) | |
228 | return -EINVAL; | |
229 | ||
230 | /* | |
231 | * In most cases we should not need to reprogram DPLL. | |
232 | * Reprogramming the DPLL is tricky, it must be done from SRAM. | |
495f71db | 233 | * (on 730, bit 13 must always be 1) |
3179a019 | 234 | */ |
39a8b086 | 235 | if (cpu_is_omap7xx()) |
495f71db BS |
236 | omap_sram_reprogram_clock(ptr->dpllctl_val, ptr->ckctl_val | 0x2000); |
237 | else | |
238 | omap_sram_reprogram_clock(ptr->dpllctl_val, ptr->ckctl_val); | |
3179a019 | 239 | |
52650505 PW |
240 | /* XXX Do we need to recalculate the tree below DPLL1 at this point? */ |
241 | ck_dpll1_p->rate = ptr->pll_rate; | |
242 | ||
3179a019 TL |
243 | return 0; |
244 | } | |
245 | ||
52650505 | 246 | int omap1_clk_set_rate_dsp_domain(struct clk *clk, unsigned long rate) |
3179a019 | 247 | { |
d5e6072b RK |
248 | int dsor_exp; |
249 | u16 regval; | |
3179a019 | 250 | |
d5e6072b RK |
251 | dsor_exp = calc_dsor_exp(clk, rate); |
252 | if (dsor_exp > 3) | |
253 | dsor_exp = -EINVAL; | |
254 | if (dsor_exp < 0) | |
255 | return dsor_exp; | |
256 | ||
257 | regval = __raw_readw(DSP_CKCTL); | |
258 | regval &= ~(3 << clk->rate_offset); | |
259 | regval |= dsor_exp << clk->rate_offset; | |
260 | __raw_writew(regval, DSP_CKCTL); | |
261 | clk->rate = clk->parent->rate / (1 << dsor_exp); | |
262 | ||
263 | return 0; | |
264 | } | |
265 | ||
52650505 | 266 | long omap1_clk_round_rate_ckctl_arm(struct clk *clk, unsigned long rate) |
d5e6072b RK |
267 | { |
268 | int dsor_exp = calc_dsor_exp(clk, rate); | |
269 | if (dsor_exp < 0) | |
270 | return dsor_exp; | |
271 | if (dsor_exp > 3) | |
272 | dsor_exp = 3; | |
273 | return clk->parent->rate / (1 << dsor_exp); | |
274 | } | |
275 | ||
52650505 | 276 | int omap1_clk_set_rate_ckctl_arm(struct clk *clk, unsigned long rate) |
d5e6072b RK |
277 | { |
278 | int dsor_exp; | |
279 | u16 regval; | |
280 | ||
281 | dsor_exp = calc_dsor_exp(clk, rate); | |
282 | if (dsor_exp > 3) | |
283 | dsor_exp = -EINVAL; | |
284 | if (dsor_exp < 0) | |
285 | return dsor_exp; | |
286 | ||
287 | regval = omap_readw(ARM_CKCTL); | |
288 | regval &= ~(3 << clk->rate_offset); | |
289 | regval |= dsor_exp << clk->rate_offset; | |
290 | regval = verify_ckctl_value(regval); | |
291 | omap_writew(regval, ARM_CKCTL); | |
292 | clk->rate = clk->parent->rate / (1 << dsor_exp); | |
293 | return 0; | |
3179a019 TL |
294 | } |
295 | ||
52650505 | 296 | long omap1_round_to_table_rate(struct clk *clk, unsigned long rate) |
3179a019 TL |
297 | { |
298 | /* Find the highest supported frequency <= rate */ | |
299 | struct mpu_rate * ptr; | |
52650505 PW |
300 | long highest_rate; |
301 | unsigned long ref_rate; | |
302 | ||
af022faf | 303 | ref_rate = ck_ref_p->rate; |
3179a019 | 304 | |
3179a019 TL |
305 | highest_rate = -EINVAL; |
306 | ||
52650505 PW |
307 | for (ptr = omap1_rate_table; ptr->rate; ptr++) { |
308 | if (ptr->xtal != ref_rate) | |
3179a019 TL |
309 | continue; |
310 | ||
311 | highest_rate = ptr->rate; | |
312 | ||
313 | /* Can check only after xtal frequency check */ | |
314 | if (ptr->rate <= rate) | |
315 | break; | |
316 | } | |
317 | ||
318 | return highest_rate; | |
319 | } | |
320 | ||
321 | static unsigned calc_ext_dsor(unsigned long rate) | |
322 | { | |
323 | unsigned dsor; | |
324 | ||
325 | /* MCLK and BCLK divisor selection is not linear: | |
326 | * freq = 96MHz / dsor | |
327 | * | |
328 | * RATIO_SEL range: dsor <-> RATIO_SEL | |
329 | * 0..6: (RATIO_SEL+2) <-> (dsor-2) | |
330 | * 6..48: (8+(RATIO_SEL-6)*2) <-> ((dsor-8)/2+6) | |
331 | * Minimum dsor is 2 and maximum is 96. Odd divisors starting from 9 | |
332 | * can not be used. | |
333 | */ | |
334 | for (dsor = 2; dsor < 96; ++dsor) { | |
335 | if ((dsor & 1) && dsor > 8) | |
b824efae | 336 | continue; |
3179a019 TL |
337 | if (rate >= 96000000 / dsor) |
338 | break; | |
339 | } | |
340 | return dsor; | |
341 | } | |
342 | ||
52650505 PW |
343 | /* XXX Only needed on 1510 */ |
344 | int omap1_set_uart_rate(struct clk *clk, unsigned long rate) | |
3179a019 TL |
345 | { |
346 | unsigned int val; | |
347 | ||
fed415e4 | 348 | val = __raw_readl(clk->enable_reg); |
3179a019 TL |
349 | if (rate == 12000000) |
350 | val &= ~(1 << clk->enable_bit); | |
351 | else if (rate == 48000000) | |
352 | val |= (1 << clk->enable_bit); | |
353 | else | |
354 | return -EINVAL; | |
fed415e4 | 355 | __raw_writel(val, clk->enable_reg); |
3179a019 TL |
356 | clk->rate = rate; |
357 | ||
358 | return 0; | |
359 | } | |
360 | ||
361 | /* External clock (MCLK & BCLK) functions */ | |
52650505 | 362 | int omap1_set_ext_clk_rate(struct clk *clk, unsigned long rate) |
3179a019 TL |
363 | { |
364 | unsigned dsor; | |
365 | __u16 ratio_bits; | |
366 | ||
367 | dsor = calc_ext_dsor(rate); | |
368 | clk->rate = 96000000 / dsor; | |
369 | if (dsor > 8) | |
370 | ratio_bits = ((dsor - 8) / 2 + 6) << 2; | |
371 | else | |
372 | ratio_bits = (dsor - 2) << 2; | |
373 | ||
fed415e4 TL |
374 | ratio_bits |= __raw_readw(clk->enable_reg) & ~0xfd; |
375 | __raw_writew(ratio_bits, clk->enable_reg); | |
3179a019 TL |
376 | |
377 | return 0; | |
378 | } | |
379 | ||
52650505 | 380 | int omap1_set_sossi_rate(struct clk *clk, unsigned long rate) |
df2c2e70 ID |
381 | { |
382 | u32 l; | |
383 | int div; | |
384 | unsigned long p_rate; | |
385 | ||
386 | p_rate = clk->parent->rate; | |
387 | /* Round towards slower frequency */ | |
388 | div = (p_rate + rate - 1) / rate; | |
389 | div--; | |
390 | if (div < 0 || div > 7) | |
391 | return -EINVAL; | |
392 | ||
393 | l = omap_readl(MOD_CONF_CTRL_1); | |
394 | l &= ~(7 << 17); | |
395 | l |= div << 17; | |
396 | omap_writel(l, MOD_CONF_CTRL_1); | |
397 | ||
398 | clk->rate = p_rate / (div + 1); | |
df2c2e70 ID |
399 | |
400 | return 0; | |
401 | } | |
402 | ||
52650505 | 403 | long omap1_round_ext_clk_rate(struct clk *clk, unsigned long rate) |
3179a019 TL |
404 | { |
405 | return 96000000 / calc_ext_dsor(rate); | |
406 | } | |
407 | ||
52650505 | 408 | void omap1_init_ext_clk(struct clk *clk) |
3179a019 TL |
409 | { |
410 | unsigned dsor; | |
411 | __u16 ratio_bits; | |
412 | ||
413 | /* Determine current rate and ensure clock is based on 96MHz APLL */ | |
fed415e4 TL |
414 | ratio_bits = __raw_readw(clk->enable_reg) & ~1; |
415 | __raw_writew(ratio_bits, clk->enable_reg); | |
3179a019 TL |
416 | |
417 | ratio_bits = (ratio_bits & 0xfc) >> 2; | |
418 | if (ratio_bits > 6) | |
419 | dsor = (ratio_bits - 6) * 2 + 8; | |
420 | else | |
421 | dsor = ratio_bits + 2; | |
422 | ||
423 | clk-> rate = 96000000 / dsor; | |
424 | } | |
425 | ||
52650505 | 426 | int omap1_clk_enable(struct clk *clk) |
3179a019 TL |
427 | { |
428 | int ret = 0; | |
3ef48fac | 429 | |
3179a019 | 430 | if (clk->usecount++ == 0) { |
3ef48fac | 431 | if (clk->parent) { |
10b55794 | 432 | ret = omap1_clk_enable(clk->parent); |
3ef48fac RK |
433 | if (ret) |
434 | goto err; | |
3179a019 TL |
435 | |
436 | if (clk->flags & CLOCK_NO_IDLE_PARENT) | |
6f9c92f1 | 437 | omap1_clk_deny_idle(clk->parent); |
3179a019 TL |
438 | } |
439 | ||
548d8495 | 440 | ret = clk->ops->enable(clk); |
3ef48fac RK |
441 | if (ret) { |
442 | if (clk->parent) | |
443 | omap1_clk_disable(clk->parent); | |
444 | goto err; | |
3179a019 TL |
445 | } |
446 | } | |
3ef48fac | 447 | return ret; |
3179a019 | 448 | |
3ef48fac RK |
449 | err: |
450 | clk->usecount--; | |
3179a019 TL |
451 | return ret; |
452 | } | |
453 | ||
52650505 | 454 | void omap1_clk_disable(struct clk *clk) |
3179a019 TL |
455 | { |
456 | if (clk->usecount > 0 && !(--clk->usecount)) { | |
548d8495 | 457 | clk->ops->disable(clk); |
3179a019 | 458 | if (likely(clk->parent)) { |
10b55794 | 459 | omap1_clk_disable(clk->parent); |
3179a019 | 460 | if (clk->flags & CLOCK_NO_IDLE_PARENT) |
6f9c92f1 | 461 | omap1_clk_allow_idle(clk->parent); |
3179a019 TL |
462 | } |
463 | } | |
464 | } | |
465 | ||
10b55794 | 466 | static int omap1_clk_enable_generic(struct clk *clk) |
3179a019 TL |
467 | { |
468 | __u16 regval16; | |
469 | __u32 regval32; | |
470 | ||
c0fc18c5 | 471 | if (unlikely(clk->enable_reg == NULL)) { |
3179a019 TL |
472 | printk(KERN_ERR "clock.c: Enable for %s without enable code\n", |
473 | clk->name); | |
6f9c92f1 | 474 | return -EINVAL; |
3179a019 TL |
475 | } |
476 | ||
477 | if (clk->flags & ENABLE_REG_32BIT) { | |
fed415e4 TL |
478 | regval32 = __raw_readl(clk->enable_reg); |
479 | regval32 |= (1 << clk->enable_bit); | |
480 | __raw_writel(regval32, clk->enable_reg); | |
3179a019 | 481 | } else { |
fed415e4 TL |
482 | regval16 = __raw_readw(clk->enable_reg); |
483 | regval16 |= (1 << clk->enable_bit); | |
484 | __raw_writew(regval16, clk->enable_reg); | |
3179a019 TL |
485 | } |
486 | ||
6f9c92f1 | 487 | return 0; |
3179a019 TL |
488 | } |
489 | ||
10b55794 | 490 | static void omap1_clk_disable_generic(struct clk *clk) |
3179a019 TL |
491 | { |
492 | __u16 regval16; | |
493 | __u32 regval32; | |
494 | ||
c0fc18c5 | 495 | if (clk->enable_reg == NULL) |
3179a019 TL |
496 | return; |
497 | ||
498 | if (clk->flags & ENABLE_REG_32BIT) { | |
fed415e4 TL |
499 | regval32 = __raw_readl(clk->enable_reg); |
500 | regval32 &= ~(1 << clk->enable_bit); | |
501 | __raw_writel(regval32, clk->enable_reg); | |
3179a019 | 502 | } else { |
fed415e4 TL |
503 | regval16 = __raw_readw(clk->enable_reg); |
504 | regval16 &= ~(1 << clk->enable_bit); | |
505 | __raw_writew(regval16, clk->enable_reg); | |
3179a019 TL |
506 | } |
507 | } | |
508 | ||
52650505 PW |
509 | const struct clkops clkops_generic = { |
510 | .enable = omap1_clk_enable_generic, | |
511 | .disable = omap1_clk_disable_generic, | |
512 | }; | |
513 | ||
514 | static int omap1_clk_enable_dsp_domain(struct clk *clk) | |
515 | { | |
516 | int retval; | |
517 | ||
518 | retval = omap1_clk_enable(api_ck_p); | |
519 | if (!retval) { | |
520 | retval = omap1_clk_enable_generic(clk); | |
521 | omap1_clk_disable(api_ck_p); | |
522 | } | |
523 | ||
524 | return retval; | |
525 | } | |
526 | ||
527 | static void omap1_clk_disable_dsp_domain(struct clk *clk) | |
528 | { | |
529 | if (omap1_clk_enable(api_ck_p) == 0) { | |
530 | omap1_clk_disable_generic(clk); | |
531 | omap1_clk_disable(api_ck_p); | |
532 | } | |
533 | } | |
534 | ||
535 | const struct clkops clkops_dspck = { | |
536 | .enable = omap1_clk_enable_dsp_domain, | |
537 | .disable = omap1_clk_disable_dsp_domain, | |
548d8495 RK |
538 | }; |
539 | ||
52650505 PW |
540 | static int omap1_clk_enable_uart_functional(struct clk *clk) |
541 | { | |
542 | int ret; | |
543 | struct uart_clk *uclk; | |
544 | ||
545 | ret = omap1_clk_enable_generic(clk); | |
546 | if (ret == 0) { | |
547 | /* Set smart idle acknowledgement mode */ | |
548 | uclk = (struct uart_clk *)clk; | |
549 | omap_writeb((omap_readb(uclk->sysc_addr) & ~0x10) | 8, | |
550 | uclk->sysc_addr); | |
551 | } | |
552 | ||
553 | return ret; | |
554 | } | |
555 | ||
556 | static void omap1_clk_disable_uart_functional(struct clk *clk) | |
557 | { | |
558 | struct uart_clk *uclk; | |
559 | ||
560 | /* Set force idle acknowledgement mode */ | |
561 | uclk = (struct uart_clk *)clk; | |
562 | omap_writeb((omap_readb(uclk->sysc_addr) & ~0x18), uclk->sysc_addr); | |
563 | ||
564 | omap1_clk_disable_generic(clk); | |
565 | } | |
566 | ||
567 | const struct clkops clkops_uart = { | |
568 | .enable = omap1_clk_enable_uart_functional, | |
569 | .disable = omap1_clk_disable_uart_functional, | |
570 | }; | |
571 | ||
572 | long omap1_clk_round_rate(struct clk *clk, unsigned long rate) | |
3179a019 | 573 | { |
c0fc18c5 | 574 | if (clk->round_rate != NULL) |
3179a019 TL |
575 | return clk->round_rate(clk, rate); |
576 | ||
577 | return clk->rate; | |
578 | } | |
579 | ||
52650505 | 580 | int omap1_clk_set_rate(struct clk *clk, unsigned long rate) |
3179a019 TL |
581 | { |
582 | int ret = -EINVAL; | |
3179a019 TL |
583 | |
584 | if (clk->set_rate) | |
585 | ret = clk->set_rate(clk, rate); | |
3179a019 TL |
586 | return ret; |
587 | } | |
588 | ||
589 | /*------------------------------------------------------------------------- | |
590 | * Omap1 clock reset and init functions | |
591 | *-------------------------------------------------------------------------*/ | |
592 | ||
593 | #ifdef CONFIG_OMAP_RESET_CLOCKS | |
3179a019 | 594 | |
52650505 | 595 | void __init omap1_clk_disable_unused(struct clk *clk) |
3179a019 | 596 | { |
3179a019 TL |
597 | __u32 regval32; |
598 | ||
90afd5cb TL |
599 | /* Clocks in the DSP domain need api_ck. Just assume bootloader |
600 | * has not enabled any DSP clocks */ | |
397fcaf7 | 601 | if (clk->enable_reg == DSP_IDLECT2) { |
90afd5cb TL |
602 | printk(KERN_INFO "Skipping reset check for DSP domain " |
603 | "clock \"%s\"\n", clk->name); | |
604 | return; | |
605 | } | |
3179a019 | 606 | |
90afd5cb | 607 | /* Is the clock already disabled? */ |
fed415e4 TL |
608 | if (clk->flags & ENABLE_REG_32BIT) |
609 | regval32 = __raw_readl(clk->enable_reg); | |
610 | else | |
611 | regval32 = __raw_readw(clk->enable_reg); | |
3179a019 | 612 | |
90afd5cb TL |
613 | if ((regval32 & (1 << clk->enable_bit)) == 0) |
614 | return; | |
3179a019 | 615 | |
90afd5cb | 616 | printk(KERN_INFO "Disabling unused clock \"%s\"... ", clk->name); |
548d8495 | 617 | clk->ops->disable(clk); |
90afd5cb | 618 | printk(" done\n"); |
3179a019 | 619 | } |
3179a019 | 620 | |
3179a019 | 621 | #endif |