blob: f46206eb3a15f15025692b55aeefd57763069b8c [file] [log] [blame]
Tony Lindgren3179a012005-11-10 14:26:48 +00001/*
2 * linux/arch/arm/mach-omap1/clock.c
3 *
Paul Walmsley51c19542010-02-22 22:09:26 -07004 * Copyright (C) 2004 - 2005, 2009-2010 Nokia Corporation
Tony Lindgren3179a012005-11-10 14:26:48 +00005 * 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 */
Tony Lindgren3179a012005-11-10 14:26:48 +000014#include <linux/kernel.h>
Paul Walmsley1fe9be82012-09-27 10:33:33 -060015#include <linux/export.h>
Tony Lindgren3179a012005-11-10 14:26:48 +000016#include <linux/list.h>
17#include <linux/errno.h>
18#include <linux/err.h>
Tony Lindgren2c799ce2012-02-24 10:34:35 -080019#include <linux/io.h>
Russell Kingf8ce2542006-01-07 16:15:52 +000020#include <linux/clk.h>
Jean-Christop PLAGNIOL-VILLARD6d803ba2010-11-17 10:04:33 +010021#include <linux/clkdev.h>
Tony Lindgren3179a012005-11-10 14:26:48 +000022
Tony Lindgren90afd5c2006-09-25 13:27:20 +030023#include <asm/mach-types.h>
Tony Lindgren3179a012005-11-10 14:26:48 +000024
Tony Lindgrence491cf2009-10-20 09:40:47 -070025#include <plat/cpu.h>
26#include <plat/usb.h>
27#include <plat/clock.h>
Paul Walmsley52650502009-12-08 16:29:38 -070028#include <plat/clkdev_omap.h>
Russell King548d8492008-11-04 14:02:46 +000029
Tony Lindgren2c799ce2012-02-24 10:34:35 -080030#include <mach/hardware.h>
31
Tony Lindgren622297f2012-10-02 14:19:52 -070032#include "../plat-omap/sram.h"
33
Tony Lindgren2e3ee9f2012-02-24 10:34:34 -080034#include "iomap.h"
Tony Lindgren3179a012005-11-10 14:26:48 +000035#include "clock.h"
Paul Walmsley52650502009-12-08 16:29:38 -070036#include "opp.h"
37
38__u32 arm_idlect1_mask;
39struct clk *api_ck_p, *ck_dpll1_p, *ck_ref_p;
40
Paul Walmsley1fe9be82012-09-27 10:33:33 -060041static LIST_HEAD(clocks);
42static DEFINE_MUTEX(clocks_mutex);
43static DEFINE_SPINLOCK(clockfw_lock);
44
Paul Walmsleyfb2fc922010-07-26 16:34:28 -060045/*
Paul Walmsley52650502009-12-08 16:29:38 -070046 * Omap1 specific clock functions
Paul Walmsleyfb2fc922010-07-26 16:34:28 -060047 */
Tony Lindgren3179a012005-11-10 14:26:48 +000048
Paul Walmsley52650502009-12-08 16:29:38 -070049unsigned long omap1_uart_recalc(struct clk *clk)
Tony Lindgren3179a012005-11-10 14:26:48 +000050{
Tony Lindgrenfed415e2009-01-28 12:18:48 -070051 unsigned int val = __raw_readl(clk->enable_reg);
Russell King8b9dbc12009-02-12 10:12:59 +000052 return val & clk->enable_bit ? 48000000 : 12000000;
Tony Lindgren3179a012005-11-10 14:26:48 +000053}
54
Paul Walmsley52650502009-12-08 16:29:38 -070055unsigned long omap1_sossi_recalc(struct clk *clk)
Imre Deakdf2c2e72007-03-05 17:22:58 +020056{
57 u32 div = omap_readl(MOD_CONF_CTRL_1);
58
59 div = (div >> 17) & 0x7;
60 div++;
Russell King8b9dbc12009-02-12 10:12:59 +000061
62 return clk->parent->rate / div;
Imre Deakdf2c2e72007-03-05 17:22:58 +020063}
64
Tony Lindgren3179a012005-11-10 14:26:48 +000065static void omap1_clk_allow_idle(struct clk *clk)
66{
67 struct arm_idlect1_clk * iclk = (struct arm_idlect1_clk *)clk;
68
69 if (!(clk->flags & CLOCK_IDLE_CONTROL))
70 return;
71
72 if (iclk->no_idle_count > 0 && !(--iclk->no_idle_count))
73 arm_idlect1_mask |= 1 << iclk->idlect_shift;
74}
75
76static void omap1_clk_deny_idle(struct clk *clk)
77{
78 struct arm_idlect1_clk * iclk = (struct arm_idlect1_clk *)clk;
79
80 if (!(clk->flags & CLOCK_IDLE_CONTROL))
81 return;
82
83 if (iclk->no_idle_count++ == 0)
84 arm_idlect1_mask &= ~(1 << iclk->idlect_shift);
85}
86
87static __u16 verify_ckctl_value(__u16 newval)
88{
89 /* This function checks for following limitations set
90 * by the hardware (all conditions must be true):
91 * DSPMMU_CK == DSP_CK or DSPMMU_CK == DSP_CK/2
92 * ARM_CK >= TC_CK
93 * DSP_CK >= TC_CK
94 * DSPMMU_CK >= TC_CK
95 *
96 * In addition following rules are enforced:
97 * LCD_CK <= TC_CK
98 * ARMPER_CK <= TC_CK
99 *
100 * However, maximum frequencies are not checked for!
101 */
102 __u8 per_exp;
103 __u8 lcd_exp;
104 __u8 arm_exp;
105 __u8 dsp_exp;
106 __u8 tc_exp;
107 __u8 dspmmu_exp;
108
109 per_exp = (newval >> CKCTL_PERDIV_OFFSET) & 3;
110 lcd_exp = (newval >> CKCTL_LCDDIV_OFFSET) & 3;
111 arm_exp = (newval >> CKCTL_ARMDIV_OFFSET) & 3;
112 dsp_exp = (newval >> CKCTL_DSPDIV_OFFSET) & 3;
113 tc_exp = (newval >> CKCTL_TCDIV_OFFSET) & 3;
114 dspmmu_exp = (newval >> CKCTL_DSPMMUDIV_OFFSET) & 3;
115
116 if (dspmmu_exp < dsp_exp)
117 dspmmu_exp = dsp_exp;
118 if (dspmmu_exp > dsp_exp+1)
119 dspmmu_exp = dsp_exp+1;
120 if (tc_exp < arm_exp)
121 tc_exp = arm_exp;
122 if (tc_exp < dspmmu_exp)
123 tc_exp = dspmmu_exp;
124 if (tc_exp > lcd_exp)
125 lcd_exp = tc_exp;
126 if (tc_exp > per_exp)
127 per_exp = tc_exp;
128
129 newval &= 0xf000;
130 newval |= per_exp << CKCTL_PERDIV_OFFSET;
131 newval |= lcd_exp << CKCTL_LCDDIV_OFFSET;
132 newval |= arm_exp << CKCTL_ARMDIV_OFFSET;
133 newval |= dsp_exp << CKCTL_DSPDIV_OFFSET;
134 newval |= tc_exp << CKCTL_TCDIV_OFFSET;
135 newval |= dspmmu_exp << CKCTL_DSPMMUDIV_OFFSET;
136
137 return newval;
138}
139
140static int calc_dsor_exp(struct clk *clk, unsigned long rate)
141{
142 /* Note: If target frequency is too low, this function will return 4,
143 * which is invalid value. Caller must check for this value and act
144 * accordingly.
145 *
146 * Note: This function does not check for following limitations set
147 * by the hardware (all conditions must be true):
148 * DSPMMU_CK == DSP_CK or DSPMMU_CK == DSP_CK/2
149 * ARM_CK >= TC_CK
150 * DSP_CK >= TC_CK
151 * DSPMMU_CK >= TC_CK
152 */
153 unsigned long realrate;
154 struct clk * parent;
155 unsigned dsor_exp;
156
Tony Lindgren3179a012005-11-10 14:26:48 +0000157 parent = clk->parent;
Russell Kingc0fc18c52008-09-05 15:10:27 +0100158 if (unlikely(parent == NULL))
Tony Lindgren3179a012005-11-10 14:26:48 +0000159 return -EIO;
160
161 realrate = parent->rate;
162 for (dsor_exp=0; dsor_exp<4; dsor_exp++) {
163 if (realrate <= rate)
164 break;
165
166 realrate /= 2;
167 }
168
169 return dsor_exp;
170}
171
Paul Walmsley52650502009-12-08 16:29:38 -0700172unsigned long omap1_ckctl_recalc(struct clk *clk)
Tony Lindgren3179a012005-11-10 14:26:48 +0000173{
Tony Lindgren3179a012005-11-10 14:26:48 +0000174 /* Calculate divisor encoded as 2-bit exponent */
Russell King8b9dbc12009-02-12 10:12:59 +0000175 int dsor = 1 << (3 & (omap_readw(ARM_CKCTL) >> clk->rate_offset));
Tony Lindgren3179a012005-11-10 14:26:48 +0000176
Russell King8b9dbc12009-02-12 10:12:59 +0000177 return clk->parent->rate / dsor;
Tony Lindgren3179a012005-11-10 14:26:48 +0000178}
179
Paul Walmsley52650502009-12-08 16:29:38 -0700180unsigned long omap1_ckctl_recalc_dsp_domain(struct clk *clk)
Tony Lindgren3179a012005-11-10 14:26:48 +0000181{
182 int dsor;
183
184 /* Calculate divisor encoded as 2-bit exponent
185 *
186 * The clock control bits are in DSP domain,
187 * so api_ck is needed for access.
188 * Note that DSP_CKCTL virt addr = phys addr, so
189 * we must use __raw_readw() instead of omap_readw().
190 */
Paul Walmsley52650502009-12-08 16:29:38 -0700191 omap1_clk_enable(api_ck_p);
Tony Lindgren3179a012005-11-10 14:26:48 +0000192 dsor = 1 << (3 & (__raw_readw(DSP_CKCTL) >> clk->rate_offset));
Paul Walmsley52650502009-12-08 16:29:38 -0700193 omap1_clk_disable(api_ck_p);
Tony Lindgren3179a012005-11-10 14:26:48 +0000194
Russell King8b9dbc12009-02-12 10:12:59 +0000195 return clk->parent->rate / dsor;
Tony Lindgren3179a012005-11-10 14:26:48 +0000196}
197
198/* MPU virtual clock functions */
Paul Walmsley52650502009-12-08 16:29:38 -0700199int omap1_select_table_rate(struct clk *clk, unsigned long rate)
Tony Lindgren3179a012005-11-10 14:26:48 +0000200{
201 /* Find the highest supported frequency <= rate and switch to it */
202 struct mpu_rate * ptr;
Paul Walmsleyeeb37112012-04-13 06:34:32 -0600203 unsigned long ref_rate;
Tony Lindgren3179a012005-11-10 14:26:48 +0000204
Paul Walmsleyaf022fa2010-01-19 17:30:55 -0700205 ref_rate = ck_ref_p->rate;
Paul Walmsley52650502009-12-08 16:29:38 -0700206
207 for (ptr = omap1_rate_table; ptr->rate; ptr++) {
Janusz Krzysztofik24ce2702011-12-08 18:01:41 -0800208 if (!(ptr->flags & cpu_mask))
209 continue;
210
Paul Walmsley52650502009-12-08 16:29:38 -0700211 if (ptr->xtal != ref_rate)
Tony Lindgren3179a012005-11-10 14:26:48 +0000212 continue;
213
Tony Lindgren3179a012005-11-10 14:26:48 +0000214 /* Can check only after xtal frequency check */
215 if (ptr->rate <= rate)
216 break;
217 }
218
219 if (!ptr->rate)
220 return -EINVAL;
221
222 /*
223 * In most cases we should not need to reprogram DPLL.
224 * Reprogramming the DPLL is tricky, it must be done from SRAM.
225 */
Janusz Krzysztofikf9e59082011-12-01 22:16:26 +0100226 omap_sram_reprogram_clock(ptr->dpllctl_val, ptr->ckctl_val);
Tony Lindgren3179a012005-11-10 14:26:48 +0000227
Paul Walmsley52650502009-12-08 16:29:38 -0700228 /* XXX Do we need to recalculate the tree below DPLL1 at this point? */
229 ck_dpll1_p->rate = ptr->pll_rate;
230
Tony Lindgren3179a012005-11-10 14:26:48 +0000231 return 0;
232}
233
Paul Walmsley52650502009-12-08 16:29:38 -0700234int omap1_clk_set_rate_dsp_domain(struct clk *clk, unsigned long rate)
Tony Lindgren3179a012005-11-10 14:26:48 +0000235{
Russell Kingd5e60722009-02-08 16:07:46 +0000236 int dsor_exp;
237 u16 regval;
Tony Lindgren3179a012005-11-10 14:26:48 +0000238
Russell Kingd5e60722009-02-08 16:07:46 +0000239 dsor_exp = calc_dsor_exp(clk, rate);
240 if (dsor_exp > 3)
241 dsor_exp = -EINVAL;
242 if (dsor_exp < 0)
243 return dsor_exp;
Tony Lindgren3179a012005-11-10 14:26:48 +0000244
Russell Kingd5e60722009-02-08 16:07:46 +0000245 regval = __raw_readw(DSP_CKCTL);
246 regval &= ~(3 << clk->rate_offset);
247 regval |= dsor_exp << clk->rate_offset;
248 __raw_writew(regval, DSP_CKCTL);
249 clk->rate = clk->parent->rate / (1 << dsor_exp);
Tony Lindgren3179a012005-11-10 14:26:48 +0000250
Russell Kingd5e60722009-02-08 16:07:46 +0000251 return 0;
252}
253
Paul Walmsley52650502009-12-08 16:29:38 -0700254long omap1_clk_round_rate_ckctl_arm(struct clk *clk, unsigned long rate)
Russell Kingd5e60722009-02-08 16:07:46 +0000255{
256 int dsor_exp = calc_dsor_exp(clk, rate);
257 if (dsor_exp < 0)
258 return dsor_exp;
259 if (dsor_exp > 3)
260 dsor_exp = 3;
261 return clk->parent->rate / (1 << dsor_exp);
262}
263
Paul Walmsley52650502009-12-08 16:29:38 -0700264int omap1_clk_set_rate_ckctl_arm(struct clk *clk, unsigned long rate)
Russell Kingd5e60722009-02-08 16:07:46 +0000265{
266 int dsor_exp;
267 u16 regval;
268
269 dsor_exp = calc_dsor_exp(clk, rate);
270 if (dsor_exp > 3)
271 dsor_exp = -EINVAL;
272 if (dsor_exp < 0)
273 return dsor_exp;
274
275 regval = omap_readw(ARM_CKCTL);
276 regval &= ~(3 << clk->rate_offset);
277 regval |= dsor_exp << clk->rate_offset;
278 regval = verify_ckctl_value(regval);
279 omap_writew(regval, ARM_CKCTL);
280 clk->rate = clk->parent->rate / (1 << dsor_exp);
281 return 0;
Tony Lindgren3179a012005-11-10 14:26:48 +0000282}
283
Paul Walmsley52650502009-12-08 16:29:38 -0700284long omap1_round_to_table_rate(struct clk *clk, unsigned long rate)
Tony Lindgren3179a012005-11-10 14:26:48 +0000285{
286 /* Find the highest supported frequency <= rate */
287 struct mpu_rate * ptr;
Paul Walmsley52650502009-12-08 16:29:38 -0700288 long highest_rate;
289 unsigned long ref_rate;
290
Paul Walmsleyaf022fa2010-01-19 17:30:55 -0700291 ref_rate = ck_ref_p->rate;
Tony Lindgren3179a012005-11-10 14:26:48 +0000292
Tony Lindgren3179a012005-11-10 14:26:48 +0000293 highest_rate = -EINVAL;
294
Paul Walmsley52650502009-12-08 16:29:38 -0700295 for (ptr = omap1_rate_table; ptr->rate; ptr++) {
Janusz Krzysztofik24ce2702011-12-08 18:01:41 -0800296 if (!(ptr->flags & cpu_mask))
297 continue;
298
Paul Walmsley52650502009-12-08 16:29:38 -0700299 if (ptr->xtal != ref_rate)
Tony Lindgren3179a012005-11-10 14:26:48 +0000300 continue;
301
302 highest_rate = ptr->rate;
303
304 /* Can check only after xtal frequency check */
305 if (ptr->rate <= rate)
306 break;
307 }
308
309 return highest_rate;
310}
311
312static unsigned calc_ext_dsor(unsigned long rate)
313{
314 unsigned dsor;
315
316 /* MCLK and BCLK divisor selection is not linear:
317 * freq = 96MHz / dsor
318 *
319 * RATIO_SEL range: dsor <-> RATIO_SEL
320 * 0..6: (RATIO_SEL+2) <-> (dsor-2)
321 * 6..48: (8+(RATIO_SEL-6)*2) <-> ((dsor-8)/2+6)
322 * Minimum dsor is 2 and maximum is 96. Odd divisors starting from 9
323 * can not be used.
324 */
325 for (dsor = 2; dsor < 96; ++dsor) {
326 if ((dsor & 1) && dsor > 8)
Tony Lindgrenb824efa2006-04-02 17:46:20 +0100327 continue;
Tony Lindgren3179a012005-11-10 14:26:48 +0000328 if (rate >= 96000000 / dsor)
329 break;
330 }
331 return dsor;
332}
333
Paul Walmsley52650502009-12-08 16:29:38 -0700334/* XXX Only needed on 1510 */
335int omap1_set_uart_rate(struct clk *clk, unsigned long rate)
Tony Lindgren3179a012005-11-10 14:26:48 +0000336{
337 unsigned int val;
338
Tony Lindgrenfed415e2009-01-28 12:18:48 -0700339 val = __raw_readl(clk->enable_reg);
Tony Lindgren3179a012005-11-10 14:26:48 +0000340 if (rate == 12000000)
341 val &= ~(1 << clk->enable_bit);
342 else if (rate == 48000000)
343 val |= (1 << clk->enable_bit);
344 else
345 return -EINVAL;
Tony Lindgrenfed415e2009-01-28 12:18:48 -0700346 __raw_writel(val, clk->enable_reg);
Tony Lindgren3179a012005-11-10 14:26:48 +0000347 clk->rate = rate;
348
349 return 0;
350}
351
352/* External clock (MCLK & BCLK) functions */
Paul Walmsley52650502009-12-08 16:29:38 -0700353int omap1_set_ext_clk_rate(struct clk *clk, unsigned long rate)
Tony Lindgren3179a012005-11-10 14:26:48 +0000354{
355 unsigned dsor;
356 __u16 ratio_bits;
357
358 dsor = calc_ext_dsor(rate);
359 clk->rate = 96000000 / dsor;
360 if (dsor > 8)
361 ratio_bits = ((dsor - 8) / 2 + 6) << 2;
362 else
363 ratio_bits = (dsor - 2) << 2;
364
Tony Lindgrenfed415e2009-01-28 12:18:48 -0700365 ratio_bits |= __raw_readw(clk->enable_reg) & ~0xfd;
366 __raw_writew(ratio_bits, clk->enable_reg);
Tony Lindgren3179a012005-11-10 14:26:48 +0000367
368 return 0;
369}
370
Paul Walmsley52650502009-12-08 16:29:38 -0700371int omap1_set_sossi_rate(struct clk *clk, unsigned long rate)
Imre Deakdf2c2e72007-03-05 17:22:58 +0200372{
373 u32 l;
374 int div;
375 unsigned long p_rate;
376
377 p_rate = clk->parent->rate;
378 /* Round towards slower frequency */
379 div = (p_rate + rate - 1) / rate;
380 div--;
381 if (div < 0 || div > 7)
382 return -EINVAL;
383
384 l = omap_readl(MOD_CONF_CTRL_1);
385 l &= ~(7 << 17);
386 l |= div << 17;
387 omap_writel(l, MOD_CONF_CTRL_1);
388
389 clk->rate = p_rate / (div + 1);
Imre Deakdf2c2e72007-03-05 17:22:58 +0200390
391 return 0;
392}
393
Paul Walmsley52650502009-12-08 16:29:38 -0700394long omap1_round_ext_clk_rate(struct clk *clk, unsigned long rate)
Tony Lindgren3179a012005-11-10 14:26:48 +0000395{
396 return 96000000 / calc_ext_dsor(rate);
397}
398
Paul Walmsley52650502009-12-08 16:29:38 -0700399void omap1_init_ext_clk(struct clk *clk)
Tony Lindgren3179a012005-11-10 14:26:48 +0000400{
401 unsigned dsor;
402 __u16 ratio_bits;
403
404 /* Determine current rate and ensure clock is based on 96MHz APLL */
Tony Lindgrenfed415e2009-01-28 12:18:48 -0700405 ratio_bits = __raw_readw(clk->enable_reg) & ~1;
406 __raw_writew(ratio_bits, clk->enable_reg);
Tony Lindgren3179a012005-11-10 14:26:48 +0000407
408 ratio_bits = (ratio_bits & 0xfc) >> 2;
409 if (ratio_bits > 6)
410 dsor = (ratio_bits - 6) * 2 + 8;
411 else
412 dsor = ratio_bits + 2;
413
414 clk-> rate = 96000000 / dsor;
415}
416
Paul Walmsley52650502009-12-08 16:29:38 -0700417int omap1_clk_enable(struct clk *clk)
Tony Lindgren3179a012005-11-10 14:26:48 +0000418{
419 int ret = 0;
Tony Lindgren3179a012005-11-10 14:26:48 +0000420
Russell King3ef48fac2009-04-05 12:27:24 +0100421 if (clk->usecount++ == 0) {
422 if (clk->parent) {
423 ret = omap1_clk_enable(clk->parent);
424 if (ret)
425 goto err;
Tony Lindgren3179a012005-11-10 14:26:48 +0000426
427 if (clk->flags & CLOCK_NO_IDLE_PARENT)
Dirk Behme6f9c92f2006-12-06 17:13:51 -0800428 omap1_clk_deny_idle(clk->parent);
Tony Lindgren3179a012005-11-10 14:26:48 +0000429 }
430
Russell King548d8492008-11-04 14:02:46 +0000431 ret = clk->ops->enable(clk);
Russell King3ef48fac2009-04-05 12:27:24 +0100432 if (ret) {
433 if (clk->parent)
434 omap1_clk_disable(clk->parent);
435 goto err;
Tony Lindgren3179a012005-11-10 14:26:48 +0000436 }
437 }
Russell King3ef48fac2009-04-05 12:27:24 +0100438 return ret;
Tony Lindgren3179a012005-11-10 14:26:48 +0000439
Russell King3ef48fac2009-04-05 12:27:24 +0100440err:
441 clk->usecount--;
Tony Lindgren3179a012005-11-10 14:26:48 +0000442 return ret;
443}
444
Paul Walmsley52650502009-12-08 16:29:38 -0700445void omap1_clk_disable(struct clk *clk)
Tony Lindgren3179a012005-11-10 14:26:48 +0000446{
447 if (clk->usecount > 0 && !(--clk->usecount)) {
Russell King548d8492008-11-04 14:02:46 +0000448 clk->ops->disable(clk);
Tony Lindgren3179a012005-11-10 14:26:48 +0000449 if (likely(clk->parent)) {
Tony Lindgren10b55792006-01-17 15:30:42 -0800450 omap1_clk_disable(clk->parent);
Tony Lindgren3179a012005-11-10 14:26:48 +0000451 if (clk->flags & CLOCK_NO_IDLE_PARENT)
Dirk Behme6f9c92f2006-12-06 17:13:51 -0800452 omap1_clk_allow_idle(clk->parent);
Tony Lindgren3179a012005-11-10 14:26:48 +0000453 }
454 }
455}
456
Tony Lindgren10b55792006-01-17 15:30:42 -0800457static int omap1_clk_enable_generic(struct clk *clk)
Tony Lindgren3179a012005-11-10 14:26:48 +0000458{
459 __u16 regval16;
460 __u32 regval32;
461
Russell Kingc0fc18c52008-09-05 15:10:27 +0100462 if (unlikely(clk->enable_reg == NULL)) {
Tony Lindgren3179a012005-11-10 14:26:48 +0000463 printk(KERN_ERR "clock.c: Enable for %s without enable code\n",
464 clk->name);
Dirk Behme6f9c92f2006-12-06 17:13:51 -0800465 return -EINVAL;
Tony Lindgren3179a012005-11-10 14:26:48 +0000466 }
467
468 if (clk->flags & ENABLE_REG_32BIT) {
Tony Lindgrenfed415e2009-01-28 12:18:48 -0700469 regval32 = __raw_readl(clk->enable_reg);
470 regval32 |= (1 << clk->enable_bit);
471 __raw_writel(regval32, clk->enable_reg);
Tony Lindgren3179a012005-11-10 14:26:48 +0000472 } else {
Tony Lindgrenfed415e2009-01-28 12:18:48 -0700473 regval16 = __raw_readw(clk->enable_reg);
474 regval16 |= (1 << clk->enable_bit);
475 __raw_writew(regval16, clk->enable_reg);
Tony Lindgren3179a012005-11-10 14:26:48 +0000476 }
477
Dirk Behme6f9c92f2006-12-06 17:13:51 -0800478 return 0;
Tony Lindgren3179a012005-11-10 14:26:48 +0000479}
480
Tony Lindgren10b55792006-01-17 15:30:42 -0800481static void omap1_clk_disable_generic(struct clk *clk)
Tony Lindgren3179a012005-11-10 14:26:48 +0000482{
483 __u16 regval16;
484 __u32 regval32;
485
Russell Kingc0fc18c52008-09-05 15:10:27 +0100486 if (clk->enable_reg == NULL)
Tony Lindgren3179a012005-11-10 14:26:48 +0000487 return;
488
489 if (clk->flags & ENABLE_REG_32BIT) {
Tony Lindgrenfed415e2009-01-28 12:18:48 -0700490 regval32 = __raw_readl(clk->enable_reg);
491 regval32 &= ~(1 << clk->enable_bit);
492 __raw_writel(regval32, clk->enable_reg);
Tony Lindgren3179a012005-11-10 14:26:48 +0000493 } else {
Tony Lindgrenfed415e2009-01-28 12:18:48 -0700494 regval16 = __raw_readw(clk->enable_reg);
495 regval16 &= ~(1 << clk->enable_bit);
496 __raw_writew(regval16, clk->enable_reg);
Tony Lindgren3179a012005-11-10 14:26:48 +0000497 }
498}
499
Paul Walmsley52650502009-12-08 16:29:38 -0700500const struct clkops clkops_generic = {
501 .enable = omap1_clk_enable_generic,
502 .disable = omap1_clk_disable_generic,
Russell King548d8492008-11-04 14:02:46 +0000503};
504
Paul Walmsley52650502009-12-08 16:29:38 -0700505static int omap1_clk_enable_dsp_domain(struct clk *clk)
506{
507 int retval;
508
509 retval = omap1_clk_enable(api_ck_p);
510 if (!retval) {
511 retval = omap1_clk_enable_generic(clk);
512 omap1_clk_disable(api_ck_p);
513 }
514
515 return retval;
516}
517
518static void omap1_clk_disable_dsp_domain(struct clk *clk)
519{
520 if (omap1_clk_enable(api_ck_p) == 0) {
521 omap1_clk_disable_generic(clk);
522 omap1_clk_disable(api_ck_p);
523 }
524}
525
526const struct clkops clkops_dspck = {
527 .enable = omap1_clk_enable_dsp_domain,
528 .disable = omap1_clk_disable_dsp_domain,
529};
530
Paul Walmsleyfb2fc922010-07-26 16:34:28 -0600531/* XXX SYSC register handling does not belong in the clock framework */
532static int omap1_clk_enable_uart_functional_16xx(struct clk *clk)
Paul Walmsley52650502009-12-08 16:29:38 -0700533{
534 int ret;
535 struct uart_clk *uclk;
536
537 ret = omap1_clk_enable_generic(clk);
538 if (ret == 0) {
539 /* Set smart idle acknowledgement mode */
540 uclk = (struct uart_clk *)clk;
541 omap_writeb((omap_readb(uclk->sysc_addr) & ~0x10) | 8,
542 uclk->sysc_addr);
543 }
544
545 return ret;
546}
547
Paul Walmsleyfb2fc922010-07-26 16:34:28 -0600548/* XXX SYSC register handling does not belong in the clock framework */
549static void omap1_clk_disable_uart_functional_16xx(struct clk *clk)
Paul Walmsley52650502009-12-08 16:29:38 -0700550{
551 struct uart_clk *uclk;
552
553 /* Set force idle acknowledgement mode */
554 uclk = (struct uart_clk *)clk;
555 omap_writeb((omap_readb(uclk->sysc_addr) & ~0x18), uclk->sysc_addr);
556
557 omap1_clk_disable_generic(clk);
558}
559
Paul Walmsleyfb2fc922010-07-26 16:34:28 -0600560/* XXX SYSC register handling does not belong in the clock framework */
561const struct clkops clkops_uart_16xx = {
562 .enable = omap1_clk_enable_uart_functional_16xx,
563 .disable = omap1_clk_disable_uart_functional_16xx,
Paul Walmsley52650502009-12-08 16:29:38 -0700564};
565
566long omap1_clk_round_rate(struct clk *clk, unsigned long rate)
Tony Lindgren3179a012005-11-10 14:26:48 +0000567{
Russell Kingc0fc18c52008-09-05 15:10:27 +0100568 if (clk->round_rate != NULL)
Tony Lindgren3179a012005-11-10 14:26:48 +0000569 return clk->round_rate(clk, rate);
570
571 return clk->rate;
572}
573
Paul Walmsley52650502009-12-08 16:29:38 -0700574int omap1_clk_set_rate(struct clk *clk, unsigned long rate)
Tony Lindgren3179a012005-11-10 14:26:48 +0000575{
576 int ret = -EINVAL;
Tony Lindgren3179a012005-11-10 14:26:48 +0000577
578 if (clk->set_rate)
579 ret = clk->set_rate(clk, rate);
Tony Lindgren3179a012005-11-10 14:26:48 +0000580 return ret;
581}
582
Paul Walmsleyfb2fc922010-07-26 16:34:28 -0600583/*
Tony Lindgren3179a012005-11-10 14:26:48 +0000584 * Omap1 clock reset and init functions
Paul Walmsleyfb2fc922010-07-26 16:34:28 -0600585 */
Tony Lindgren3179a012005-11-10 14:26:48 +0000586
587#ifdef CONFIG_OMAP_RESET_CLOCKS
Tony Lindgren3179a012005-11-10 14:26:48 +0000588
Felipe Balbi5838bb62010-05-20 12:31:04 -0600589void omap1_clk_disable_unused(struct clk *clk)
Tony Lindgren3179a012005-11-10 14:26:48 +0000590{
Tony Lindgren3179a012005-11-10 14:26:48 +0000591 __u32 regval32;
592
Tony Lindgren90afd5c2006-09-25 13:27:20 +0300593 /* Clocks in the DSP domain need api_ck. Just assume bootloader
594 * has not enabled any DSP clocks */
Russell King397fcaf2008-09-05 15:46:19 +0100595 if (clk->enable_reg == DSP_IDLECT2) {
Paul Walmsley7852ec02012-07-26 00:54:26 -0600596 pr_info("Skipping reset check for DSP domain clock \"%s\"\n",
597 clk->name);
Tony Lindgren90afd5c2006-09-25 13:27:20 +0300598 return;
Tony Lindgren3179a012005-11-10 14:26:48 +0000599 }
600
Tony Lindgren90afd5c2006-09-25 13:27:20 +0300601 /* Is the clock already disabled? */
Tony Lindgrenfed415e2009-01-28 12:18:48 -0700602 if (clk->flags & ENABLE_REG_32BIT)
603 regval32 = __raw_readl(clk->enable_reg);
604 else
605 regval32 = __raw_readw(clk->enable_reg);
Tony Lindgren90afd5c2006-09-25 13:27:20 +0300606
607 if ((regval32 & (1 << clk->enable_bit)) == 0)
608 return;
609
Tony Lindgren90afd5c2006-09-25 13:27:20 +0300610 printk(KERN_INFO "Disabling unused clock \"%s\"... ", clk->name);
Russell King548d8492008-11-04 14:02:46 +0000611 clk->ops->disable(clk);
Tony Lindgren90afd5c2006-09-25 13:27:20 +0300612 printk(" done\n");
Tony Lindgren3179a012005-11-10 14:26:48 +0000613}
Tony Lindgren3179a012005-11-10 14:26:48 +0000614
Tony Lindgren3179a012005-11-10 14:26:48 +0000615#endif
Paul Walmsley1fe9be82012-09-27 10:33:33 -0600616
617
618int clk_enable(struct clk *clk)
619{
620 unsigned long flags;
621 int ret;
622
623 if (clk == NULL || IS_ERR(clk))
624 return -EINVAL;
625
626 spin_lock_irqsave(&clockfw_lock, flags);
627 ret = omap1_clk_enable(clk);
628 spin_unlock_irqrestore(&clockfw_lock, flags);
629
630 return ret;
631}
632EXPORT_SYMBOL(clk_enable);
633
634void clk_disable(struct clk *clk)
635{
636 unsigned long flags;
637
638 if (clk == NULL || IS_ERR(clk))
639 return;
640
641 spin_lock_irqsave(&clockfw_lock, flags);
642 if (clk->usecount == 0) {
643 pr_err("Trying disable clock %s with 0 usecount\n",
644 clk->name);
645 WARN_ON(1);
646 goto out;
647 }
648
649 omap1_clk_disable(clk);
650
651out:
652 spin_unlock_irqrestore(&clockfw_lock, flags);
653}
654EXPORT_SYMBOL(clk_disable);
655
656unsigned long clk_get_rate(struct clk *clk)
657{
658 unsigned long flags;
659 unsigned long ret;
660
661 if (clk == NULL || IS_ERR(clk))
662 return 0;
663
664 spin_lock_irqsave(&clockfw_lock, flags);
665 ret = clk->rate;
666 spin_unlock_irqrestore(&clockfw_lock, flags);
667
668 return ret;
669}
670EXPORT_SYMBOL(clk_get_rate);
671
672/*
673 * Optional clock functions defined in include/linux/clk.h
674 */
675
676long clk_round_rate(struct clk *clk, unsigned long rate)
677{
678 unsigned long flags;
679 long ret;
680
681 if (clk == NULL || IS_ERR(clk))
682 return 0;
683
684 spin_lock_irqsave(&clockfw_lock, flags);
685 ret = omap1_clk_round_rate(clk, rate);
686 spin_unlock_irqrestore(&clockfw_lock, flags);
687
688 return ret;
689}
690EXPORT_SYMBOL(clk_round_rate);
691
692int clk_set_rate(struct clk *clk, unsigned long rate)
693{
694 unsigned long flags;
695 int ret = -EINVAL;
696
697 if (clk == NULL || IS_ERR(clk))
698 return ret;
699
700 spin_lock_irqsave(&clockfw_lock, flags);
701 ret = omap1_clk_set_rate(clk, rate);
702 if (ret == 0)
703 propagate_rate(clk);
704 spin_unlock_irqrestore(&clockfw_lock, flags);
705
706 return ret;
707}
708EXPORT_SYMBOL(clk_set_rate);
709
710int clk_set_parent(struct clk *clk, struct clk *parent)
711{
712 WARN_ONCE(1, "clk_set_parent() not implemented for OMAP1\n");
713
714 return -EINVAL;
715}
716EXPORT_SYMBOL(clk_set_parent);
717
718struct clk *clk_get_parent(struct clk *clk)
719{
720 return clk->parent;
721}
722EXPORT_SYMBOL(clk_get_parent);
723
724/*
725 * OMAP specific clock functions shared between omap1 and omap2
726 */
727
728int __initdata mpurate;
729
730/*
731 * By default we use the rate set by the bootloader.
732 * You can override this with mpurate= cmdline option.
733 */
734static int __init omap_clk_setup(char *str)
735{
736 get_option(&str, &mpurate);
737
738 if (!mpurate)
739 return 1;
740
741 if (mpurate < 1000)
742 mpurate *= 1000000;
743
744 return 1;
745}
746__setup("mpurate=", omap_clk_setup);
747
748/* Used for clocks that always have same value as the parent clock */
749unsigned long followparent_recalc(struct clk *clk)
750{
751 return clk->parent->rate;
752}
753
754/*
755 * Used for clocks that have the same value as the parent clock,
756 * divided by some factor
757 */
758unsigned long omap_fixed_divisor_recalc(struct clk *clk)
759{
760 WARN_ON(!clk->fixed_div);
761
762 return clk->parent->rate / clk->fixed_div;
763}
764
765void clk_reparent(struct clk *child, struct clk *parent)
766{
767 list_del_init(&child->sibling);
768 if (parent)
769 list_add(&child->sibling, &parent->children);
770 child->parent = parent;
771
772 /* now do the debugfs renaming to reattach the child
773 to the proper parent */
774}
775
776/* Propagate rate to children */
777void propagate_rate(struct clk *tclk)
778{
779 struct clk *clkp;
780
781 list_for_each_entry(clkp, &tclk->children, sibling) {
782 if (clkp->recalc)
783 clkp->rate = clkp->recalc(clkp);
784 propagate_rate(clkp);
785 }
786}
787
788static LIST_HEAD(root_clks);
789
790/**
791 * recalculate_root_clocks - recalculate and propagate all root clocks
792 *
793 * Recalculates all root clocks (clocks with no parent), which if the
794 * clock's .recalc is set correctly, should also propagate their rates.
795 * Called at init.
796 */
797void recalculate_root_clocks(void)
798{
799 struct clk *clkp;
800
801 list_for_each_entry(clkp, &root_clks, sibling) {
802 if (clkp->recalc)
803 clkp->rate = clkp->recalc(clkp);
804 propagate_rate(clkp);
805 }
806}
807
808/**
809 * clk_preinit - initialize any fields in the struct clk before clk init
810 * @clk: struct clk * to initialize
811 *
812 * Initialize any struct clk fields needed before normal clk initialization
813 * can run. No return value.
814 */
815void clk_preinit(struct clk *clk)
816{
817 INIT_LIST_HEAD(&clk->children);
818}
819
820int clk_register(struct clk *clk)
821{
822 if (clk == NULL || IS_ERR(clk))
823 return -EINVAL;
824
825 /*
826 * trap out already registered clocks
827 */
828 if (clk->node.next || clk->node.prev)
829 return 0;
830
831 mutex_lock(&clocks_mutex);
832 if (clk->parent)
833 list_add(&clk->sibling, &clk->parent->children);
834 else
835 list_add(&clk->sibling, &root_clks);
836
837 list_add(&clk->node, &clocks);
838 if (clk->init)
839 clk->init(clk);
840 mutex_unlock(&clocks_mutex);
841
842 return 0;
843}
844EXPORT_SYMBOL(clk_register);
845
846void clk_unregister(struct clk *clk)
847{
848 if (clk == NULL || IS_ERR(clk))
849 return;
850
851 mutex_lock(&clocks_mutex);
852 list_del(&clk->sibling);
853 list_del(&clk->node);
854 mutex_unlock(&clocks_mutex);
855}
856EXPORT_SYMBOL(clk_unregister);
857
858void clk_enable_init_clocks(void)
859{
860 struct clk *clkp;
861
862 list_for_each_entry(clkp, &clocks, node)
863 if (clkp->flags & ENABLE_ON_INIT)
864 clk_enable(clkp);
865}
866
867/**
868 * omap_clk_get_by_name - locate OMAP struct clk by its name
869 * @name: name of the struct clk to locate
870 *
871 * Locate an OMAP struct clk by its name. Assumes that struct clk
872 * names are unique. Returns NULL if not found or a pointer to the
873 * struct clk if found.
874 */
875struct clk *omap_clk_get_by_name(const char *name)
876{
877 struct clk *c;
878 struct clk *ret = NULL;
879
880 mutex_lock(&clocks_mutex);
881
882 list_for_each_entry(c, &clocks, node) {
883 if (!strcmp(c->name, name)) {
884 ret = c;
885 break;
886 }
887 }
888
889 mutex_unlock(&clocks_mutex);
890
891 return ret;
892}
893
894int omap_clk_enable_autoidle_all(void)
895{
896 struct clk *c;
897 unsigned long flags;
898
899 spin_lock_irqsave(&clockfw_lock, flags);
900
901 list_for_each_entry(c, &clocks, node)
902 if (c->ops->allow_idle)
903 c->ops->allow_idle(c);
904
905 spin_unlock_irqrestore(&clockfw_lock, flags);
906
907 return 0;
908}
909
910int omap_clk_disable_autoidle_all(void)
911{
912 struct clk *c;
913 unsigned long flags;
914
915 spin_lock_irqsave(&clockfw_lock, flags);
916
917 list_for_each_entry(c, &clocks, node)
918 if (c->ops->deny_idle)
919 c->ops->deny_idle(c);
920
921 spin_unlock_irqrestore(&clockfw_lock, flags);
922
923 return 0;
924}
925
926/*
927 * Low level helpers
928 */
929static int clkll_enable_null(struct clk *clk)
930{
931 return 0;
932}
933
934static void clkll_disable_null(struct clk *clk)
935{
936}
937
938const struct clkops clkops_null = {
939 .enable = clkll_enable_null,
940 .disable = clkll_disable_null,
941};
942
943/*
944 * Dummy clock
945 *
946 * Used for clock aliases that are needed on some OMAPs, but not others
947 */
948struct clk dummy_ck = {
949 .name = "dummy",
950 .ops = &clkops_null,
951};
952
953/*
954 *
955 */
956
957#ifdef CONFIG_OMAP_RESET_CLOCKS
958/*
959 * Disable any unused clocks left on by the bootloader
960 */
961static int __init clk_disable_unused(void)
962{
963 struct clk *ck;
964 unsigned long flags;
965
966 pr_info("clock: disabling unused clocks to save power\n");
967
968 spin_lock_irqsave(&clockfw_lock, flags);
969 list_for_each_entry(ck, &clocks, node) {
970 if (ck->ops == &clkops_null)
971 continue;
972
973 if (ck->usecount > 0 || !ck->enable_reg)
974 continue;
975
976 omap1_clk_disable_unused(ck);
977 }
978 spin_unlock_irqrestore(&clockfw_lock, flags);
979
980 return 0;
981}
982late_initcall(clk_disable_unused);
983late_initcall(omap_clk_enable_autoidle_all);
984#endif
985
986#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS)
987/*
988 * debugfs support to trace clock tree hierarchy and attributes
989 */
990
991#include <linux/debugfs.h>
992#include <linux/seq_file.h>
993
994static struct dentry *clk_debugfs_root;
995
996static int clk_dbg_show_summary(struct seq_file *s, void *unused)
997{
998 struct clk *c;
999 struct clk *pa;
1000
1001 mutex_lock(&clocks_mutex);
1002 seq_printf(s, "%-30s %-30s %-10s %s\n",
1003 "clock-name", "parent-name", "rate", "use-count");
1004
1005 list_for_each_entry(c, &clocks, node) {
1006 pa = c->parent;
1007 seq_printf(s, "%-30s %-30s %-10lu %d\n",
1008 c->name, pa ? pa->name : "none", c->rate,
1009 c->usecount);
1010 }
1011 mutex_unlock(&clocks_mutex);
1012
1013 return 0;
1014}
1015
1016static int clk_dbg_open(struct inode *inode, struct file *file)
1017{
1018 return single_open(file, clk_dbg_show_summary, inode->i_private);
1019}
1020
1021static const struct file_operations debug_clock_fops = {
1022 .open = clk_dbg_open,
1023 .read = seq_read,
1024 .llseek = seq_lseek,
1025 .release = single_release,
1026};
1027
1028static int clk_debugfs_register_one(struct clk *c)
1029{
1030 int err;
1031 struct dentry *d;
1032 struct clk *pa = c->parent;
1033
1034 d = debugfs_create_dir(c->name, pa ? pa->dent : clk_debugfs_root);
1035 if (!d)
1036 return -ENOMEM;
1037 c->dent = d;
1038
1039 d = debugfs_create_u8("usecount", S_IRUGO, c->dent, (u8 *)&c->usecount);
1040 if (!d) {
1041 err = -ENOMEM;
1042 goto err_out;
1043 }
1044 d = debugfs_create_u32("rate", S_IRUGO, c->dent, (u32 *)&c->rate);
1045 if (!d) {
1046 err = -ENOMEM;
1047 goto err_out;
1048 }
1049 d = debugfs_create_x32("flags", S_IRUGO, c->dent, (u32 *)&c->flags);
1050 if (!d) {
1051 err = -ENOMEM;
1052 goto err_out;
1053 }
1054 return 0;
1055
1056err_out:
1057 debugfs_remove_recursive(c->dent);
1058 return err;
1059}
1060
1061static int clk_debugfs_register(struct clk *c)
1062{
1063 int err;
1064 struct clk *pa = c->parent;
1065
1066 if (pa && !pa->dent) {
1067 err = clk_debugfs_register(pa);
1068 if (err)
1069 return err;
1070 }
1071
1072 if (!c->dent) {
1073 err = clk_debugfs_register_one(c);
1074 if (err)
1075 return err;
1076 }
1077 return 0;
1078}
1079
1080static int __init clk_debugfs_init(void)
1081{
1082 struct clk *c;
1083 struct dentry *d;
1084 int err;
1085
1086 d = debugfs_create_dir("clock", NULL);
1087 if (!d)
1088 return -ENOMEM;
1089 clk_debugfs_root = d;
1090
1091 list_for_each_entry(c, &clocks, node) {
1092 err = clk_debugfs_register(c);
1093 if (err)
1094 goto err_out;
1095 }
1096
1097 d = debugfs_create_file("summary", S_IRUGO,
1098 d, NULL, &debug_clock_fops);
1099 if (!d)
1100 return -ENOMEM;
1101
1102 return 0;
1103err_out:
1104 debugfs_remove_recursive(clk_debugfs_root);
1105 return err;
1106}
1107late_initcall(clk_debugfs_init);
1108
1109#endif /* defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS) */