aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/jz4740
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2010-07-17 07:10:00 -0400
committerRalf Baechle <ralf@linux-mips.org>2010-08-05 08:26:12 -0400
commit570a0bb82f0b5c2c6324153010e72c3f0c26a7a3 (patch)
tree65324ac4cd279e4f10edc580599a8a7dad48d7d7 /arch/mips/jz4740
parent83ccf69d8f118306e90af703f32109edb6c1e4a1 (diff)
MIPS: JZ4740: Add clock API support.
Add support for managing the clocks found on JZ4740 SoC through the Linux clock API. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/1466/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/jz4740')
-rw-r--r--arch/mips/jz4740/clock-debugfs.c109
-rw-r--r--arch/mips/jz4740/clock.c924
-rw-r--r--arch/mips/jz4740/clock.h76
3 files changed, 1109 insertions, 0 deletions
diff --git a/arch/mips/jz4740/clock-debugfs.c b/arch/mips/jz4740/clock-debugfs.c
new file mode 100644
index 000000000000..330a0f2bf17b
--- /dev/null
+++ b/arch/mips/jz4740/clock-debugfs.c
@@ -0,0 +1,109 @@
1/*
2 * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
3 * JZ4740 SoC clock support debugfs entries
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * You should have received a copy of the GNU General Public License along
11 * with this program; if not, write to the Free Software Foundation, Inc.,
12 * 675 Mass Ave, Cambridge, MA 02139, USA.
13 *
14 */
15
16#include <linux/kernel.h>
17#include <linux/module.h>
18#include <linux/clk.h>
19#include <linux/err.h>
20
21#include <linux/debugfs.h>
22#include <linux/uaccess.h>
23
24#include <asm/mach-jz4740/clock.h>
25#include "clock.h"
26
27static struct dentry *jz4740_clock_debugfs;
28
29static int jz4740_clock_debugfs_show_enabled(void *data, uint64_t *value)
30{
31 struct clk *clk = data;
32 *value = clk_is_enabled(clk);
33
34 return 0;
35}
36
37static int jz4740_clock_debugfs_set_enabled(void *data, uint64_t value)
38{
39 struct clk *clk = data;
40
41 if (value)
42 return clk_enable(clk);
43 else
44 clk_disable(clk);
45
46 return 0;
47}
48
49DEFINE_SIMPLE_ATTRIBUTE(jz4740_clock_debugfs_ops_enabled,
50 jz4740_clock_debugfs_show_enabled,
51 jz4740_clock_debugfs_set_enabled,
52 "%llu\n");
53
54static int jz4740_clock_debugfs_show_rate(void *data, uint64_t *value)
55{
56 struct clk *clk = data;
57 *value = clk_get_rate(clk);
58
59 return 0;
60}
61
62DEFINE_SIMPLE_ATTRIBUTE(jz4740_clock_debugfs_ops_rate,
63 jz4740_clock_debugfs_show_rate,
64 NULL,
65 "%llu\n");
66
67void jz4740_clock_debugfs_add_clk(struct clk *clk)
68{
69 if (!jz4740_clock_debugfs)
70 return;
71
72 clk->debugfs_entry = debugfs_create_dir(clk->name, jz4740_clock_debugfs);
73 debugfs_create_file("rate", S_IWUGO | S_IRUGO, clk->debugfs_entry, clk,
74 &jz4740_clock_debugfs_ops_rate);
75 debugfs_create_file("enabled", S_IRUGO, clk->debugfs_entry, clk,
76 &jz4740_clock_debugfs_ops_enabled);
77
78 if (clk->parent) {
79 char parent_path[100];
80 snprintf(parent_path, 100, "../%s", clk->parent->name);
81 clk->debugfs_parent_entry = debugfs_create_symlink("parent",
82 clk->debugfs_entry,
83 parent_path);
84 }
85}
86
87/* TODO: Locking */
88void jz4740_clock_debugfs_update_parent(struct clk *clk)
89{
90 if (clk->debugfs_parent_entry)
91 debugfs_remove(clk->debugfs_parent_entry);
92
93 if (clk->parent) {
94 char parent_path[100];
95 snprintf(parent_path, 100, "../%s", clk->parent->name);
96 clk->debugfs_parent_entry = debugfs_create_symlink("parent",
97 clk->debugfs_entry,
98 parent_path);
99 } else {
100 clk->debugfs_parent_entry = NULL;
101 }
102}
103
104void jz4740_clock_debugfs_init(void)
105{
106 jz4740_clock_debugfs = debugfs_create_dir("jz4740-clock", NULL);
107 if (IS_ERR(jz4740_clock_debugfs))
108 jz4740_clock_debugfs = NULL;
109}
diff --git a/arch/mips/jz4740/clock.c b/arch/mips/jz4740/clock.c
new file mode 100644
index 000000000000..118a8a5562dd
--- /dev/null
+++ b/arch/mips/jz4740/clock.c
@@ -0,0 +1,924 @@
1/*
2 * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
3 * JZ4740 SoC clock support
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * You should have received a copy of the GNU General Public License along
11 * with this program; if not, write to the Free Software Foundation, Inc.,
12 * 675 Mass Ave, Cambridge, MA 02139, USA.
13 *
14 */
15
16#include <linux/kernel.h>
17#include <linux/errno.h>
18#include <linux/clk.h>
19#include <linux/spinlock.h>
20#include <linux/io.h>
21#include <linux/module.h>
22#include <linux/list.h>
23#include <linux/err.h>
24
25#include <asm/mach-jz4740/clock.h>
26#include <asm/mach-jz4740/base.h>
27
28#include "clock.h"
29
30#define JZ_REG_CLOCK_CTRL 0x00
31#define JZ_REG_CLOCK_LOW_POWER 0x04
32#define JZ_REG_CLOCK_PLL 0x10
33#define JZ_REG_CLOCK_GATE 0x20
34#define JZ_REG_CLOCK_SLEEP_CTRL 0x24
35#define JZ_REG_CLOCK_I2S 0x60
36#define JZ_REG_CLOCK_LCD 0x64
37#define JZ_REG_CLOCK_MMC 0x68
38#define JZ_REG_CLOCK_UHC 0x6C
39#define JZ_REG_CLOCK_SPI 0x74
40
41#define JZ_CLOCK_CTRL_I2S_SRC_PLL BIT(31)
42#define JZ_CLOCK_CTRL_KO_ENABLE BIT(30)
43#define JZ_CLOCK_CTRL_UDC_SRC_PLL BIT(29)
44#define JZ_CLOCK_CTRL_UDIV_MASK 0x1f800000
45#define JZ_CLOCK_CTRL_CHANGE_ENABLE BIT(22)
46#define JZ_CLOCK_CTRL_PLL_HALF BIT(21)
47#define JZ_CLOCK_CTRL_LDIV_MASK 0x001f0000
48#define JZ_CLOCK_CTRL_UDIV_OFFSET 23
49#define JZ_CLOCK_CTRL_LDIV_OFFSET 16
50#define JZ_CLOCK_CTRL_MDIV_OFFSET 12
51#define JZ_CLOCK_CTRL_PDIV_OFFSET 8
52#define JZ_CLOCK_CTRL_HDIV_OFFSET 4
53#define JZ_CLOCK_CTRL_CDIV_OFFSET 0
54
55#define JZ_CLOCK_GATE_UART0 BIT(0)
56#define JZ_CLOCK_GATE_TCU BIT(1)
57#define JZ_CLOCK_GATE_RTC BIT(2)
58#define JZ_CLOCK_GATE_I2C BIT(3)
59#define JZ_CLOCK_GATE_SPI BIT(4)
60#define JZ_CLOCK_GATE_AIC BIT(5)
61#define JZ_CLOCK_GATE_I2S BIT(6)
62#define JZ_CLOCK_GATE_MMC BIT(7)
63#define JZ_CLOCK_GATE_ADC BIT(8)
64#define JZ_CLOCK_GATE_CIM BIT(9)
65#define JZ_CLOCK_GATE_LCD BIT(10)
66#define JZ_CLOCK_GATE_UDC BIT(11)
67#define JZ_CLOCK_GATE_DMAC BIT(12)
68#define JZ_CLOCK_GATE_IPU BIT(13)
69#define JZ_CLOCK_GATE_UHC BIT(14)
70#define JZ_CLOCK_GATE_UART1 BIT(15)
71
72#define JZ_CLOCK_I2S_DIV_MASK 0x01ff
73
74#define JZ_CLOCK_LCD_DIV_MASK 0x01ff
75
76#define JZ_CLOCK_MMC_DIV_MASK 0x001f
77
78#define JZ_CLOCK_UHC_DIV_MASK 0x000f
79
80#define JZ_CLOCK_SPI_SRC_PLL BIT(31)
81#define JZ_CLOCK_SPI_DIV_MASK 0x000f
82
83#define JZ_CLOCK_PLL_M_MASK 0x01ff
84#define JZ_CLOCK_PLL_N_MASK 0x001f
85#define JZ_CLOCK_PLL_OD_MASK 0x0003
86#define JZ_CLOCK_PLL_STABLE BIT(10)
87#define JZ_CLOCK_PLL_BYPASS BIT(9)
88#define JZ_CLOCK_PLL_ENABLED BIT(8)
89#define JZ_CLOCK_PLL_STABLIZE_MASK 0x000f
90#define JZ_CLOCK_PLL_M_OFFSET 23
91#define JZ_CLOCK_PLL_N_OFFSET 18
92#define JZ_CLOCK_PLL_OD_OFFSET 16
93
94#define JZ_CLOCK_LOW_POWER_MODE_DOZE BIT(2)
95#define JZ_CLOCK_LOW_POWER_MODE_SLEEP BIT(0)
96
97#define JZ_CLOCK_SLEEP_CTRL_SUSPEND_UHC BIT(7)
98#define JZ_CLOCK_SLEEP_CTRL_ENABLE_UDC BIT(6)
99
100static void __iomem *jz_clock_base;
101static spinlock_t jz_clock_lock;
102static LIST_HEAD(jz_clocks);
103
104struct main_clk {
105 struct clk clk;
106 uint32_t div_offset;
107};
108
109struct divided_clk {
110 struct clk clk;
111 uint32_t reg;
112 uint32_t mask;
113};
114
115struct static_clk {
116 struct clk clk;
117 unsigned long rate;
118};
119
120static uint32_t jz_clk_reg_read(int reg)
121{
122 return readl(jz_clock_base + reg);
123}
124
125static void jz_clk_reg_write_mask(int reg, uint32_t val, uint32_t mask)
126{
127 uint32_t val2;
128
129 spin_lock(&jz_clock_lock);
130 val2 = readl(jz_clock_base + reg);
131 val2 &= ~mask;
132 val2 |= val;
133 writel(val2, jz_clock_base + reg);
134 spin_unlock(&jz_clock_lock);
135}
136
137static void jz_clk_reg_set_bits(int reg, uint32_t mask)
138{
139 uint32_t val;
140
141 spin_lock(&jz_clock_lock);
142 val = readl(jz_clock_base + reg);
143 val |= mask;
144 writel(val, jz_clock_base + reg);
145 spin_unlock(&jz_clock_lock);
146}
147
148static void jz_clk_reg_clear_bits(int reg, uint32_t mask)
149{
150 uint32_t val;
151
152 spin_lock(&jz_clock_lock);
153 val = readl(jz_clock_base + reg);
154 val &= ~mask;
155 writel(val, jz_clock_base + reg);
156 spin_unlock(&jz_clock_lock);
157}
158
159static int jz_clk_enable_gating(struct clk *clk)
160{
161 if (clk->gate_bit == JZ4740_CLK_NOT_GATED)
162 return -EINVAL;
163
164 jz_clk_reg_clear_bits(JZ_REG_CLOCK_GATE, clk->gate_bit);
165 return 0;
166}
167
168static int jz_clk_disable_gating(struct clk *clk)
169{
170 if (clk->gate_bit == JZ4740_CLK_NOT_GATED)
171 return -EINVAL;
172
173 jz_clk_reg_set_bits(JZ_REG_CLOCK_GATE, clk->gate_bit);
174 return 0;
175}
176
177static int jz_clk_is_enabled_gating(struct clk *clk)
178{
179 if (clk->gate_bit == JZ4740_CLK_NOT_GATED)
180 return 1;
181
182 return !(jz_clk_reg_read(JZ_REG_CLOCK_GATE) & clk->gate_bit);
183}
184
185static unsigned long jz_clk_static_get_rate(struct clk *clk)
186{
187 return ((struct static_clk *)clk)->rate;
188}
189
190static int jz_clk_ko_enable(struct clk *clk)
191{
192 jz_clk_reg_set_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_KO_ENABLE);
193 return 0;
194}
195
196static int jz_clk_ko_disable(struct clk *clk)
197{
198 jz_clk_reg_clear_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_KO_ENABLE);
199 return 0;
200}
201
202static int jz_clk_ko_is_enabled(struct clk *clk)
203{
204 return !!(jz_clk_reg_read(JZ_REG_CLOCK_CTRL) & JZ_CLOCK_CTRL_KO_ENABLE);
205}
206
207static const int pllno[] = {1, 2, 2, 4};
208
209static unsigned long jz_clk_pll_get_rate(struct clk *clk)
210{
211 uint32_t val;
212 int m;
213 int n;
214 int od;
215
216 val = jz_clk_reg_read(JZ_REG_CLOCK_PLL);
217
218 if (val & JZ_CLOCK_PLL_BYPASS)
219 return clk_get_rate(clk->parent);
220
221 m = ((val >> 23) & 0x1ff) + 2;
222 n = ((val >> 18) & 0x1f) + 2;
223 od = (val >> 16) & 0x3;
224
225 return ((clk_get_rate(clk->parent) / n) * m) / pllno[od];
226}
227
228static unsigned long jz_clk_pll_half_get_rate(struct clk *clk)
229{
230 uint32_t reg;
231
232 reg = jz_clk_reg_read(JZ_REG_CLOCK_CTRL);
233 if (reg & JZ_CLOCK_CTRL_PLL_HALF)
234 return jz_clk_pll_get_rate(clk->parent);
235 return jz_clk_pll_get_rate(clk->parent) >> 1;
236}
237
238static const int jz_clk_main_divs[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
239
240static unsigned long jz_clk_main_round_rate(struct clk *clk, unsigned long rate)
241{
242 unsigned long parent_rate = jz_clk_pll_get_rate(clk->parent);
243 int div;
244
245 div = parent_rate / rate;
246 if (div > 32)
247 return parent_rate / 32;
248 else if (div < 1)
249 return parent_rate;
250
251 div &= (0x3 << (ffs(div) - 1));
252
253 return parent_rate / div;
254}
255
256static unsigned long jz_clk_main_get_rate(struct clk *clk)
257{
258 struct main_clk *mclk = (struct main_clk *)clk;
259 uint32_t div;
260
261 div = jz_clk_reg_read(JZ_REG_CLOCK_CTRL);
262
263 div >>= mclk->div_offset;
264 div &= 0xf;
265
266 if (div >= ARRAY_SIZE(jz_clk_main_divs))
267 div = ARRAY_SIZE(jz_clk_main_divs) - 1;
268
269 return jz_clk_pll_get_rate(clk->parent) / jz_clk_main_divs[div];
270}
271
272static int jz_clk_main_set_rate(struct clk *clk, unsigned long rate)
273{
274 struct main_clk *mclk = (struct main_clk *)clk;
275 int i;
276 int div;
277 unsigned long parent_rate = jz_clk_pll_get_rate(clk->parent);
278
279 rate = jz_clk_main_round_rate(clk, rate);
280
281 div = parent_rate / rate;
282
283 i = (ffs(div) - 1) << 1;
284 if (i > 0 && !(div & BIT(i-1)))
285 i -= 1;
286
287 jz_clk_reg_write_mask(JZ_REG_CLOCK_CTRL, i << mclk->div_offset,
288 0xf << mclk->div_offset);
289
290 return 0;
291}
292
293static struct clk_ops jz_clk_static_ops = {
294 .get_rate = jz_clk_static_get_rate,
295 .enable = jz_clk_enable_gating,
296 .disable = jz_clk_disable_gating,
297 .is_enabled = jz_clk_is_enabled_gating,
298};
299
300static struct static_clk jz_clk_ext = {
301 .clk = {
302 .name = "ext",
303 .gate_bit = JZ4740_CLK_NOT_GATED,
304 .ops = &jz_clk_static_ops,
305 },
306};
307
308static struct clk_ops jz_clk_pll_ops = {
309 .get_rate = jz_clk_pll_get_rate,
310};
311
312static struct clk jz_clk_pll = {
313 .name = "pll",
314 .parent = &jz_clk_ext.clk,
315 .ops = &jz_clk_pll_ops,
316};
317
318static struct clk_ops jz_clk_pll_half_ops = {
319 .get_rate = jz_clk_pll_half_get_rate,
320};
321
322static struct clk jz_clk_pll_half = {
323 .name = "pll half",
324 .parent = &jz_clk_pll,
325 .ops = &jz_clk_pll_half_ops,
326};
327
328static const struct clk_ops jz_clk_main_ops = {
329 .get_rate = jz_clk_main_get_rate,
330 .set_rate = jz_clk_main_set_rate,
331 .round_rate = jz_clk_main_round_rate,
332};
333
334static struct main_clk jz_clk_cpu = {
335 .clk = {
336 .name = "cclk",
337 .parent = &jz_clk_pll,
338 .ops = &jz_clk_main_ops,
339 },
340 .div_offset = JZ_CLOCK_CTRL_CDIV_OFFSET,
341};
342
343static struct main_clk jz_clk_memory = {
344 .clk = {
345 .name = "mclk",
346 .parent = &jz_clk_pll,
347 .ops = &jz_clk_main_ops,
348 },
349 .div_offset = JZ_CLOCK_CTRL_MDIV_OFFSET,
350};
351
352static struct main_clk jz_clk_high_speed_peripheral = {
353 .clk = {
354 .name = "hclk",
355 .parent = &jz_clk_pll,
356 .ops = &jz_clk_main_ops,
357 },
358 .div_offset = JZ_CLOCK_CTRL_HDIV_OFFSET,
359};
360
361
362static struct main_clk jz_clk_low_speed_peripheral = {
363 .clk = {
364 .name = "pclk",
365 .parent = &jz_clk_pll,
366 .ops = &jz_clk_main_ops,
367 },
368 .div_offset = JZ_CLOCK_CTRL_PDIV_OFFSET,
369};
370
371static const struct clk_ops jz_clk_ko_ops = {
372 .enable = jz_clk_ko_enable,
373 .disable = jz_clk_ko_disable,
374 .is_enabled = jz_clk_ko_is_enabled,
375};
376
377static struct clk jz_clk_ko = {
378 .name = "cko",
379 .parent = &jz_clk_memory.clk,
380 .ops = &jz_clk_ko_ops,
381};
382
383static int jz_clk_spi_set_parent(struct clk *clk, struct clk *parent)
384{
385 if (parent == &jz_clk_pll)
386 jz_clk_reg_set_bits(JZ_CLOCK_SPI_SRC_PLL, JZ_REG_CLOCK_SPI);
387 else if (parent == &jz_clk_ext.clk)
388 jz_clk_reg_clear_bits(JZ_CLOCK_SPI_SRC_PLL, JZ_REG_CLOCK_SPI);
389 else
390 return -EINVAL;
391
392 clk->parent = parent;
393
394 return 0;
395}
396
397static int jz_clk_i2s_set_parent(struct clk *clk, struct clk *parent)
398{
399 if (parent == &jz_clk_pll_half)
400 jz_clk_reg_set_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_I2S_SRC_PLL);
401 else if (parent == &jz_clk_ext.clk)
402 jz_clk_reg_clear_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_I2S_SRC_PLL);
403 else
404 return -EINVAL;
405
406 clk->parent = parent;
407
408 return 0;
409}
410
411static int jz_clk_udc_enable(struct clk *clk)
412{
413 jz_clk_reg_set_bits(JZ_REG_CLOCK_SLEEP_CTRL,
414 JZ_CLOCK_SLEEP_CTRL_ENABLE_UDC);
415
416 return 0;
417}
418
419static int jz_clk_udc_disable(struct clk *clk)
420{
421 jz_clk_reg_clear_bits(JZ_REG_CLOCK_SLEEP_CTRL,
422 JZ_CLOCK_SLEEP_CTRL_ENABLE_UDC);
423
424 return 0;
425}
426
427static int jz_clk_udc_is_enabled(struct clk *clk)
428{
429 return !!(jz_clk_reg_read(JZ_REG_CLOCK_SLEEP_CTRL) &
430 JZ_CLOCK_SLEEP_CTRL_ENABLE_UDC);
431}
432
433static int jz_clk_udc_set_parent(struct clk *clk, struct clk *parent)
434{
435 if (parent == &jz_clk_pll_half)
436 jz_clk_reg_set_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_UDC_SRC_PLL);
437 else if (parent == &jz_clk_ext.clk)
438 jz_clk_reg_clear_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_UDC_SRC_PLL);
439 else
440 return -EINVAL;
441
442 clk->parent = parent;
443
444 return 0;
445}
446
447static int jz_clk_udc_set_rate(struct clk *clk, unsigned long rate)
448{
449 int div;
450
451 if (clk->parent == &jz_clk_ext.clk)
452 return -EINVAL;
453
454 div = clk_get_rate(clk->parent) / rate - 1;
455
456 if (div < 0)
457 div = 0;
458 else if (div > 63)
459 div = 63;
460
461 jz_clk_reg_write_mask(JZ_REG_CLOCK_CTRL, div << JZ_CLOCK_CTRL_UDIV_OFFSET,
462 JZ_CLOCK_CTRL_UDIV_MASK);
463 return 0;
464}
465
466static unsigned long jz_clk_udc_get_rate(struct clk *clk)
467{
468 int div;
469
470 if (clk->parent == &jz_clk_ext.clk)
471 return clk_get_rate(clk->parent);
472
473 div = (jz_clk_reg_read(JZ_REG_CLOCK_CTRL) & JZ_CLOCK_CTRL_UDIV_MASK);
474 div >>= JZ_CLOCK_CTRL_UDIV_OFFSET;
475 div += 1;
476
477 return clk_get_rate(clk->parent) / div;
478}
479
480static unsigned long jz_clk_divided_get_rate(struct clk *clk)
481{
482 struct divided_clk *dclk = (struct divided_clk *)clk;
483 int div;
484
485 if (clk->parent == &jz_clk_ext.clk)
486 return clk_get_rate(clk->parent);
487
488 div = (jz_clk_reg_read(dclk->reg) & dclk->mask) + 1;
489
490 return clk_get_rate(clk->parent) / div;
491}
492
493static int jz_clk_divided_set_rate(struct clk *clk, unsigned long rate)
494{
495 struct divided_clk *dclk = (struct divided_clk *)clk;
496 int div;
497
498 if (clk->parent == &jz_clk_ext.clk)
499 return -EINVAL;
500
501 div = clk_get_rate(clk->parent) / rate - 1;
502
503 if (div < 0)
504 div = 0;
505 else if (div > dclk->mask)
506 div = dclk->mask;
507
508 jz_clk_reg_write_mask(dclk->reg, div, dclk->mask);
509
510 return 0;
511}
512
513static unsigned long jz_clk_ldclk_round_rate(struct clk *clk, unsigned long rate)
514{
515 int div;
516 unsigned long parent_rate = jz_clk_pll_half_get_rate(clk->parent);
517
518 if (rate > 150000000)
519 return 150000000;
520
521 div = parent_rate / rate;
522 if (div < 1)
523 div = 1;
524 else if (div > 32)
525 div = 32;
526
527 return parent_rate / div;
528}
529
530static int jz_clk_ldclk_set_rate(struct clk *clk, unsigned long rate)
531{
532 int div;
533
534 if (rate > 150000000)
535 return -EINVAL;
536
537 div = jz_clk_pll_half_get_rate(clk->parent) / rate - 1;
538 if (div < 0)
539 div = 0;
540 else if (div > 31)
541 div = 31;
542
543 jz_clk_reg_write_mask(JZ_REG_CLOCK_CTRL, div << JZ_CLOCK_CTRL_LDIV_OFFSET,
544 JZ_CLOCK_CTRL_LDIV_MASK);
545
546 return 0;
547}
548
549static unsigned long jz_clk_ldclk_get_rate(struct clk *clk)
550{
551 int div;
552
553 div = jz_clk_reg_read(JZ_REG_CLOCK_CTRL) & JZ_CLOCK_CTRL_LDIV_MASK;
554 div >>= JZ_CLOCK_CTRL_LDIV_OFFSET;
555
556 return jz_clk_pll_half_get_rate(clk->parent) / (div + 1);
557}
558
559static const struct clk_ops jz_clk_ops_ld = {
560 .set_rate = jz_clk_ldclk_set_rate,
561 .get_rate = jz_clk_ldclk_get_rate,
562 .round_rate = jz_clk_ldclk_round_rate,
563 .enable = jz_clk_enable_gating,
564 .disable = jz_clk_disable_gating,
565 .is_enabled = jz_clk_is_enabled_gating,
566};
567
568static struct clk jz_clk_ld = {
569 .name = "lcd",
570 .gate_bit = JZ_CLOCK_GATE_LCD,
571 .parent = &jz_clk_pll_half,
572 .ops = &jz_clk_ops_ld,
573};
574
575static const struct clk_ops jz_clk_i2s_ops = {
576 .set_rate = jz_clk_divided_set_rate,
577 .get_rate = jz_clk_divided_get_rate,
578 .enable = jz_clk_enable_gating,
579 .disable = jz_clk_disable_gating,
580 .is_enabled = jz_clk_is_enabled_gating,
581 .set_parent = jz_clk_i2s_set_parent,
582};
583
584static const struct clk_ops jz_clk_spi_ops = {
585 .set_rate = jz_clk_divided_set_rate,
586 .get_rate = jz_clk_divided_get_rate,
587 .enable = jz_clk_enable_gating,
588 .disable = jz_clk_disable_gating,
589 .is_enabled = jz_clk_is_enabled_gating,
590 .set_parent = jz_clk_spi_set_parent,
591};
592
593static const struct clk_ops jz_clk_divided_ops = {
594 .set_rate = jz_clk_divided_set_rate,
595 .get_rate = jz_clk_divided_get_rate,
596 .enable = jz_clk_enable_gating,
597 .disable = jz_clk_disable_gating,
598 .is_enabled = jz_clk_is_enabled_gating,
599};
600
601static struct divided_clk jz4740_clock_divided_clks[] = {
602 [0] = {
603 .clk = {
604 .name = "i2s",
605 .parent = &jz_clk_ext.clk,
606 .gate_bit = JZ_CLOCK_GATE_I2S,
607 .ops = &jz_clk_i2s_ops,
608 },
609 .reg = JZ_REG_CLOCK_I2S,
610 .mask = JZ_CLOCK_I2S_DIV_MASK,
611 },
612 [1] = {
613 .clk = {
614 .name = "spi",
615 .parent = &jz_clk_ext.clk,
616 .gate_bit = JZ_CLOCK_GATE_SPI,
617 .ops = &jz_clk_spi_ops,
618 },
619 .reg = JZ_REG_CLOCK_SPI,
620 .mask = JZ_CLOCK_SPI_DIV_MASK,
621 },
622 [2] = {
623 .clk = {
624 .name = "lcd_pclk",
625 .parent = &jz_clk_pll_half,
626 .gate_bit = JZ4740_CLK_NOT_GATED,
627 .ops = &jz_clk_divided_ops,
628 },
629 .reg = JZ_REG_CLOCK_LCD,
630 .mask = JZ_CLOCK_LCD_DIV_MASK,
631 },
632 [3] = {
633 .clk = {
634 .name = "mmc",
635 .parent = &jz_clk_pll_half,
636 .gate_bit = JZ_CLOCK_GATE_MMC,
637 .ops = &jz_clk_divided_ops,
638 },
639 .reg = JZ_REG_CLOCK_MMC,
640 .mask = JZ_CLOCK_MMC_DIV_MASK,
641 },
642 [4] = {
643 .clk = {
644 .name = "uhc",
645 .parent = &jz_clk_pll_half,
646 .gate_bit = JZ_CLOCK_GATE_UHC,
647 .ops = &jz_clk_divided_ops,
648 },
649 .reg = JZ_REG_CLOCK_UHC,
650 .mask = JZ_CLOCK_UHC_DIV_MASK,
651 },
652};
653
654static const struct clk_ops jz_clk_udc_ops = {
655 .set_parent = jz_clk_udc_set_parent,
656 .set_rate = jz_clk_udc_set_rate,
657 .get_rate = jz_clk_udc_get_rate,
658 .enable = jz_clk_udc_enable,
659 .disable = jz_clk_udc_disable,
660 .is_enabled = jz_clk_udc_is_enabled,
661};
662
663static const struct clk_ops jz_clk_simple_ops = {
664 .enable = jz_clk_enable_gating,
665 .disable = jz_clk_disable_gating,
666 .is_enabled = jz_clk_is_enabled_gating,
667};
668
669static struct clk jz4740_clock_simple_clks[] = {
670 [0] = {
671 .name = "udc",
672 .parent = &jz_clk_ext.clk,
673 .ops = &jz_clk_udc_ops,
674 },
675 [1] = {
676 .name = "uart0",
677 .parent = &jz_clk_ext.clk,
678 .gate_bit = JZ_CLOCK_GATE_UART0,
679 .ops = &jz_clk_simple_ops,
680 },
681 [2] = {
682 .name = "uart1",
683 .parent = &jz_clk_ext.clk,
684 .gate_bit = JZ_CLOCK_GATE_UART1,
685 .ops = &jz_clk_simple_ops,
686 },
687 [3] = {
688 .name = "dma",
689 .parent = &jz_clk_high_speed_peripheral.clk,
690 .gate_bit = JZ_CLOCK_GATE_UART0,
691 .ops = &jz_clk_simple_ops,
692 },
693 [4] = {
694 .name = "ipu",
695 .parent = &jz_clk_high_speed_peripheral.clk,
696 .gate_bit = JZ_CLOCK_GATE_IPU,
697 .ops = &jz_clk_simple_ops,
698 },
699 [5] = {
700 .name = "adc",
701 .parent = &jz_clk_ext.clk,
702 .gate_bit = JZ_CLOCK_GATE_ADC,
703 .ops = &jz_clk_simple_ops,
704 },
705 [6] = {
706 .name = "i2c",
707 .parent = &jz_clk_ext.clk,
708 .gate_bit = JZ_CLOCK_GATE_I2C,
709 .ops = &jz_clk_simple_ops,
710 },
711 [7] = {
712 .name = "aic",
713 .parent = &jz_clk_ext.clk,
714 .gate_bit = JZ_CLOCK_GATE_AIC,
715 .ops = &jz_clk_simple_ops,
716 },
717};
718
719static struct static_clk jz_clk_rtc = {
720 .clk = {
721 .name = "rtc",
722 .gate_bit = JZ_CLOCK_GATE_RTC,
723 .ops = &jz_clk_static_ops,
724 },
725 .rate = 32768,
726};
727
728int clk_enable(struct clk *clk)
729{
730 if (!clk->ops->enable)
731 return -EINVAL;
732
733 return clk->ops->enable(clk);
734}
735EXPORT_SYMBOL_GPL(clk_enable);
736
737void clk_disable(struct clk *clk)
738{
739 if (clk->ops->disable)
740 clk->ops->disable(clk);
741}
742EXPORT_SYMBOL_GPL(clk_disable);
743
744int clk_is_enabled(struct clk *clk)
745{
746 if (clk->ops->is_enabled)
747 return clk->ops->is_enabled(clk);
748
749 return 1;
750}
751
752unsigned long clk_get_rate(struct clk *clk)
753{
754 if (clk->ops->get_rate)
755 return clk->ops->get_rate(clk);
756 if (clk->parent)
757 return clk_get_rate(clk->parent);
758
759 return -EINVAL;
760}
761EXPORT_SYMBOL_GPL(clk_get_rate);
762
763int clk_set_rate(struct clk *clk, unsigned long rate)
764{
765 if (!clk->ops->set_rate)
766 return -EINVAL;
767 return clk->ops->set_rate(clk, rate);
768}
769EXPORT_SYMBOL_GPL(clk_set_rate);
770
771long clk_round_rate(struct clk *clk, unsigned long rate)
772{
773 if (clk->ops->round_rate)
774 return clk->ops->round_rate(clk, rate);
775
776 return -EINVAL;
777}
778EXPORT_SYMBOL_GPL(clk_round_rate);
779
780int clk_set_parent(struct clk *clk, struct clk *parent)
781{
782 int ret;
783 int enabled;
784
785 if (!clk->ops->set_parent)
786 return -EINVAL;
787
788 enabled = clk_is_enabled(clk);
789 if (enabled)
790 clk_disable(clk);
791 ret = clk->ops->set_parent(clk, parent);
792 if (enabled)
793 clk_enable(clk);
794
795 jz4740_clock_debugfs_update_parent(clk);
796
797 return ret;
798}
799EXPORT_SYMBOL_GPL(clk_set_parent);
800
801struct clk *clk_get(struct device *dev, const char *name)
802{
803 struct clk *clk;
804
805 list_for_each_entry(clk, &jz_clocks, list) {
806 if (strcmp(clk->name, name) == 0)
807 return clk;
808 }
809 return ERR_PTR(-ENXIO);
810}
811EXPORT_SYMBOL_GPL(clk_get);
812
813void clk_put(struct clk *clk)
814{
815}
816EXPORT_SYMBOL_GPL(clk_put);
817
818static inline void clk_add(struct clk *clk)
819{
820 list_add_tail(&clk->list, &jz_clocks);
821
822 jz4740_clock_debugfs_add_clk(clk);
823}
824
825static void clk_register_clks(void)
826{
827 size_t i;
828
829 clk_add(&jz_clk_ext.clk);
830 clk_add(&jz_clk_pll);
831 clk_add(&jz_clk_pll_half);
832 clk_add(&jz_clk_cpu.clk);
833 clk_add(&jz_clk_high_speed_peripheral.clk);
834 clk_add(&jz_clk_low_speed_peripheral.clk);
835 clk_add(&jz_clk_ko);
836 clk_add(&jz_clk_ld);
837 clk_add(&jz_clk_rtc.clk);
838
839 for (i = 0; i < ARRAY_SIZE(jz4740_clock_divided_clks); ++i)
840 clk_add(&jz4740_clock_divided_clks[i].clk);
841
842 for (i = 0; i < ARRAY_SIZE(jz4740_clock_simple_clks); ++i)
843 clk_add(&jz4740_clock_simple_clks[i]);
844}
845
846void jz4740_clock_set_wait_mode(enum jz4740_wait_mode mode)
847{
848 switch (mode) {
849 case JZ4740_WAIT_MODE_IDLE:
850 jz_clk_reg_clear_bits(JZ_REG_CLOCK_LOW_POWER, JZ_CLOCK_LOW_POWER_MODE_SLEEP);
851 break;
852 case JZ4740_WAIT_MODE_SLEEP:
853 jz_clk_reg_set_bits(JZ_REG_CLOCK_LOW_POWER, JZ_CLOCK_LOW_POWER_MODE_SLEEP);
854 break;
855 }
856}
857
858void jz4740_clock_udc_disable_auto_suspend(void)
859{
860 jz_clk_reg_clear_bits(JZ_REG_CLOCK_GATE, JZ_CLOCK_GATE_UDC);
861}
862EXPORT_SYMBOL_GPL(jz4740_clock_udc_disable_auto_suspend);
863
864void jz4740_clock_udc_enable_auto_suspend(void)
865{
866 jz_clk_reg_set_bits(JZ_REG_CLOCK_GATE, JZ_CLOCK_GATE_UDC);
867}
868EXPORT_SYMBOL_GPL(jz4740_clock_udc_enable_auto_suspend);
869
870void jz4740_clock_suspend(void)
871{
872 jz_clk_reg_set_bits(JZ_REG_CLOCK_GATE,
873 JZ_CLOCK_GATE_TCU | JZ_CLOCK_GATE_DMAC | JZ_CLOCK_GATE_UART0);
874
875 jz_clk_reg_clear_bits(JZ_REG_CLOCK_PLL, JZ_CLOCK_PLL_ENABLED);
876}
877
878void jz4740_clock_resume(void)
879{
880 uint32_t pll;
881
882 jz_clk_reg_set_bits(JZ_REG_CLOCK_PLL, JZ_CLOCK_PLL_ENABLED);
883
884 do {
885 pll = jz_clk_reg_read(JZ_REG_CLOCK_PLL);
886 } while (!(pll & JZ_CLOCK_PLL_STABLE));
887
888 jz_clk_reg_clear_bits(JZ_REG_CLOCK_GATE,
889 JZ_CLOCK_GATE_TCU | JZ_CLOCK_GATE_DMAC | JZ_CLOCK_GATE_UART0);
890}
891
892static int jz4740_clock_init(void)
893{
894 uint32_t val;
895
896 jz_clock_base = ioremap(JZ4740_CPM_BASE_ADDR, 0x100);
897 if (!jz_clock_base)
898 return -EBUSY;
899
900 spin_lock_init(&jz_clock_lock);
901
902 jz_clk_ext.rate = jz4740_clock_bdata.ext_rate;
903 jz_clk_rtc.rate = jz4740_clock_bdata.rtc_rate;
904
905 val = jz_clk_reg_read(JZ_REG_CLOCK_SPI);
906
907 if (val & JZ_CLOCK_SPI_SRC_PLL)
908 jz4740_clock_divided_clks[1].clk.parent = &jz_clk_pll_half;
909
910 val = jz_clk_reg_read(JZ_REG_CLOCK_CTRL);
911
912 if (val & JZ_CLOCK_CTRL_I2S_SRC_PLL)
913 jz4740_clock_divided_clks[0].clk.parent = &jz_clk_pll_half;
914
915 if (val & JZ_CLOCK_CTRL_UDC_SRC_PLL)
916 jz4740_clock_simple_clks[0].parent = &jz_clk_pll_half;
917
918 jz4740_clock_debugfs_init();
919
920 clk_register_clks();
921
922 return 0;
923}
924arch_initcall(jz4740_clock_init);
diff --git a/arch/mips/jz4740/clock.h b/arch/mips/jz4740/clock.h
new file mode 100644
index 000000000000..5d07499d7461
--- /dev/null
+++ b/arch/mips/jz4740/clock.h
@@ -0,0 +1,76 @@
1/*
2 * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
3 * JZ4740 SoC clock support
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * You should have received a copy of the GNU General Public License along
11 * with this program; if not, write to the Free Software Foundation, Inc.,
12 * 675 Mass Ave, Cambridge, MA 02139, USA.
13 *
14 */
15
16#ifndef __MIPS_JZ4740_CLOCK_H__
17#define __MIPS_JZ4740_CLOCK_H__
18
19#include <linux/list.h>
20
21struct jz4740_clock_board_data {
22 unsigned long ext_rate;
23 unsigned long rtc_rate;
24};
25
26extern struct jz4740_clock_board_data jz4740_clock_bdata;
27
28void jz4740_clock_suspend(void);
29void jz4740_clock_resume(void);
30
31struct clk;
32
33struct clk_ops {
34 unsigned long (*get_rate)(struct clk *clk);
35 unsigned long (*round_rate)(struct clk *clk, unsigned long rate);
36 int (*set_rate)(struct clk *clk, unsigned long rate);
37 int (*enable)(struct clk *clk);
38 int (*disable)(struct clk *clk);
39 int (*is_enabled)(struct clk *clk);
40
41 int (*set_parent)(struct clk *clk, struct clk *parent);
42
43};
44
45struct clk {
46 const char *name;
47 struct clk *parent;
48
49 uint32_t gate_bit;
50
51 const struct clk_ops *ops;
52
53 struct list_head list;
54
55#ifdef CONFIG_DEBUG_FS
56 struct dentry *debugfs_entry;
57 struct dentry *debugfs_parent_entry;
58#endif
59
60};
61
62#define JZ4740_CLK_NOT_GATED ((uint32_t)-1)
63
64int clk_is_enabled(struct clk *clk);
65
66#ifdef CONFIG_DEBUG_FS
67void jz4740_clock_debugfs_init(void);
68void jz4740_clock_debugfs_add_clk(struct clk *clk);
69void jz4740_clock_debugfs_update_parent(struct clk *clk);
70#else
71static inline void jz4740_clock_debugfs_init(void) {};
72static inline void jz4740_clock_debugfs_add_clk(struct clk *clk) {};
73static inline void jz4740_clock_debugfs_update_parent(struct clk *clk) {};
74#endif
75
76#endif