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