Commit | Line | Data |
---|---|---|
36ddf31b PM |
1 | /* |
2 | * arch/sh/kernel/cpu/sh3/clock-sh3.c | |
3 | * | |
4 | * Generic SH-3 support for the clock framework | |
5 | * | |
6 | * Copyright (C) 2005 Paul Mundt | |
7 | * | |
8 | * FRQCR parsing hacked out of arch/sh/kernel/time.c | |
9 | * | |
10 | * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka | |
11 | * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> | |
12 | * Copyright (C) 2002, 2003, 2004 Paul Mundt | |
13 | * Copyright (C) 2002 M. R. Brown <mrbrown@linux-sh.org> | |
14 | * | |
15 | * This file is subject to the terms and conditions of the GNU General Public | |
16 | * License. See the file "COPYING" in the main directory of this archive | |
17 | * for more details. | |
18 | */ | |
19 | #include <linux/init.h> | |
20 | #include <linux/kernel.h> | |
21 | #include <asm/clock.h> | |
22 | #include <asm/freq.h> | |
23 | #include <asm/io.h> | |
24 | ||
25 | static int stc_multipliers[] = { 1, 2, 3, 4, 6, 1, 1, 1 }; | |
26 | static int ifc_divisors[] = { 1, 2, 3, 4, 1, 1, 1, 1 }; | |
27 | static int pfc_divisors[] = { 1, 2, 3, 4, 6, 1, 1, 1 }; | |
28 | ||
29 | static void master_clk_init(struct clk *clk) | |
30 | { | |
9d56dd3b | 31 | int frqcr = __raw_readw(FRQCR); |
36ddf31b PM |
32 | int idx = ((frqcr & 0x2000) >> 11) | (frqcr & 0x0003); |
33 | ||
34 | clk->rate *= pfc_divisors[idx]; | |
35 | } | |
36 | ||
37 | static struct clk_ops sh3_master_clk_ops = { | |
38 | .init = master_clk_init, | |
39 | }; | |
40 | ||
b68d8201 | 41 | static unsigned long module_clk_recalc(struct clk *clk) |
36ddf31b | 42 | { |
9d56dd3b | 43 | int frqcr = __raw_readw(FRQCR); |
36ddf31b PM |
44 | int idx = ((frqcr & 0x2000) >> 11) | (frqcr & 0x0003); |
45 | ||
b68d8201 | 46 | return clk->parent->rate / pfc_divisors[idx]; |
36ddf31b PM |
47 | } |
48 | ||
49 | static struct clk_ops sh3_module_clk_ops = { | |
50 | .recalc = module_clk_recalc, | |
51 | }; | |
52 | ||
b68d8201 | 53 | static unsigned long bus_clk_recalc(struct clk *clk) |
36ddf31b | 54 | { |
9d56dd3b | 55 | int frqcr = __raw_readw(FRQCR); |
36ddf31b PM |
56 | int idx = ((frqcr & 0x8000) >> 13) | ((frqcr & 0x0030) >> 4); |
57 | ||
b68d8201 | 58 | return clk->parent->rate / stc_multipliers[idx]; |
36ddf31b PM |
59 | } |
60 | ||
61 | static struct clk_ops sh3_bus_clk_ops = { | |
62 | .recalc = bus_clk_recalc, | |
63 | }; | |
64 | ||
b68d8201 | 65 | static unsigned long cpu_clk_recalc(struct clk *clk) |
36ddf31b | 66 | { |
9d56dd3b | 67 | int frqcr = __raw_readw(FRQCR); |
36ddf31b PM |
68 | int idx = ((frqcr & 0x4000) >> 12) | ((frqcr & 0x000c) >> 2); |
69 | ||
b68d8201 | 70 | return clk->parent->rate / ifc_divisors[idx]; |
36ddf31b PM |
71 | } |
72 | ||
73 | static struct clk_ops sh3_cpu_clk_ops = { | |
74 | .recalc = cpu_clk_recalc, | |
75 | }; | |
76 | ||
77 | static struct clk_ops *sh3_clk_ops[] = { | |
78 | &sh3_master_clk_ops, | |
79 | &sh3_module_clk_ops, | |
80 | &sh3_bus_clk_ops, | |
81 | &sh3_cpu_clk_ops, | |
82 | }; | |
83 | ||
84 | void __init arch_init_clk_ops(struct clk_ops **ops, int idx) | |
85 | { | |
86 | if (idx < ARRAY_SIZE(sh3_clk_ops)) | |
87 | *ops = sh3_clk_ops[idx]; | |
88 | } | |
89 |