diff options
Diffstat (limited to 'arch/mips/bcm63xx/clk.c')
-rw-r--r-- | arch/mips/bcm63xx/clk.c | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/arch/mips/bcm63xx/clk.c b/arch/mips/bcm63xx/clk.c new file mode 100644 index 000000000000..2c68ee9ccee2 --- /dev/null +++ b/arch/mips/bcm63xx/clk.c | |||
@@ -0,0 +1,226 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr> | ||
7 | */ | ||
8 | |||
9 | #include <linux/module.h> | ||
10 | #include <linux/mutex.h> | ||
11 | #include <linux/err.h> | ||
12 | #include <linux/clk.h> | ||
13 | #include <bcm63xx_cpu.h> | ||
14 | #include <bcm63xx_io.h> | ||
15 | #include <bcm63xx_regs.h> | ||
16 | #include <bcm63xx_clk.h> | ||
17 | |||
18 | static DEFINE_MUTEX(clocks_mutex); | ||
19 | |||
20 | |||
21 | static void clk_enable_unlocked(struct clk *clk) | ||
22 | { | ||
23 | if (clk->set && (clk->usage++) == 0) | ||
24 | clk->set(clk, 1); | ||
25 | } | ||
26 | |||
27 | static void clk_disable_unlocked(struct clk *clk) | ||
28 | { | ||
29 | if (clk->set && (--clk->usage) == 0) | ||
30 | clk->set(clk, 0); | ||
31 | } | ||
32 | |||
33 | static void bcm_hwclock_set(u32 mask, int enable) | ||
34 | { | ||
35 | u32 reg; | ||
36 | |||
37 | reg = bcm_perf_readl(PERF_CKCTL_REG); | ||
38 | if (enable) | ||
39 | reg |= mask; | ||
40 | else | ||
41 | reg &= ~mask; | ||
42 | bcm_perf_writel(reg, PERF_CKCTL_REG); | ||
43 | } | ||
44 | |||
45 | /* | ||
46 | * Ethernet MAC "misc" clock: dma clocks and main clock on 6348 | ||
47 | */ | ||
48 | static void enet_misc_set(struct clk *clk, int enable) | ||
49 | { | ||
50 | u32 mask; | ||
51 | |||
52 | if (BCMCPU_IS_6338()) | ||
53 | mask = CKCTL_6338_ENET_EN; | ||
54 | else if (BCMCPU_IS_6345()) | ||
55 | mask = CKCTL_6345_ENET_EN; | ||
56 | else if (BCMCPU_IS_6348()) | ||
57 | mask = CKCTL_6348_ENET_EN; | ||
58 | else | ||
59 | /* BCMCPU_IS_6358 */ | ||
60 | mask = CKCTL_6358_EMUSB_EN; | ||
61 | bcm_hwclock_set(mask, enable); | ||
62 | } | ||
63 | |||
64 | static struct clk clk_enet_misc = { | ||
65 | .set = enet_misc_set, | ||
66 | }; | ||
67 | |||
68 | /* | ||
69 | * Ethernet MAC clocks: only revelant on 6358, silently enable misc | ||
70 | * clocks | ||
71 | */ | ||
72 | static void enetx_set(struct clk *clk, int enable) | ||
73 | { | ||
74 | if (enable) | ||
75 | clk_enable_unlocked(&clk_enet_misc); | ||
76 | else | ||
77 | clk_disable_unlocked(&clk_enet_misc); | ||
78 | |||
79 | if (BCMCPU_IS_6358()) { | ||
80 | u32 mask; | ||
81 | |||
82 | if (clk->id == 0) | ||
83 | mask = CKCTL_6358_ENET0_EN; | ||
84 | else | ||
85 | mask = CKCTL_6358_ENET1_EN; | ||
86 | bcm_hwclock_set(mask, enable); | ||
87 | } | ||
88 | } | ||
89 | |||
90 | static struct clk clk_enet0 = { | ||
91 | .id = 0, | ||
92 | .set = enetx_set, | ||
93 | }; | ||
94 | |||
95 | static struct clk clk_enet1 = { | ||
96 | .id = 1, | ||
97 | .set = enetx_set, | ||
98 | }; | ||
99 | |||
100 | /* | ||
101 | * Ethernet PHY clock | ||
102 | */ | ||
103 | static void ephy_set(struct clk *clk, int enable) | ||
104 | { | ||
105 | if (!BCMCPU_IS_6358()) | ||
106 | return; | ||
107 | bcm_hwclock_set(CKCTL_6358_EPHY_EN, enable); | ||
108 | } | ||
109 | |||
110 | |||
111 | static struct clk clk_ephy = { | ||
112 | .set = ephy_set, | ||
113 | }; | ||
114 | |||
115 | /* | ||
116 | * PCM clock | ||
117 | */ | ||
118 | static void pcm_set(struct clk *clk, int enable) | ||
119 | { | ||
120 | if (!BCMCPU_IS_6358()) | ||
121 | return; | ||
122 | bcm_hwclock_set(CKCTL_6358_PCM_EN, enable); | ||
123 | } | ||
124 | |||
125 | static struct clk clk_pcm = { | ||
126 | .set = pcm_set, | ||
127 | }; | ||
128 | |||
129 | /* | ||
130 | * USB host clock | ||
131 | */ | ||
132 | static void usbh_set(struct clk *clk, int enable) | ||
133 | { | ||
134 | if (!BCMCPU_IS_6348()) | ||
135 | return; | ||
136 | bcm_hwclock_set(CKCTL_6348_USBH_EN, enable); | ||
137 | } | ||
138 | |||
139 | static struct clk clk_usbh = { | ||
140 | .set = usbh_set, | ||
141 | }; | ||
142 | |||
143 | /* | ||
144 | * SPI clock | ||
145 | */ | ||
146 | static void spi_set(struct clk *clk, int enable) | ||
147 | { | ||
148 | u32 mask; | ||
149 | |||
150 | if (BCMCPU_IS_6338()) | ||
151 | mask = CKCTL_6338_SPI_EN; | ||
152 | else if (BCMCPU_IS_6348()) | ||
153 | mask = CKCTL_6348_SPI_EN; | ||
154 | else | ||
155 | /* BCMCPU_IS_6358 */ | ||
156 | mask = CKCTL_6358_SPI_EN; | ||
157 | bcm_hwclock_set(mask, enable); | ||
158 | } | ||
159 | |||
160 | static struct clk clk_spi = { | ||
161 | .set = spi_set, | ||
162 | }; | ||
163 | |||
164 | /* | ||
165 | * Internal peripheral clock | ||
166 | */ | ||
167 | static struct clk clk_periph = { | ||
168 | .rate = (50 * 1000 * 1000), | ||
169 | }; | ||
170 | |||
171 | |||
172 | /* | ||
173 | * Linux clock API implementation | ||
174 | */ | ||
175 | int clk_enable(struct clk *clk) | ||
176 | { | ||
177 | mutex_lock(&clocks_mutex); | ||
178 | clk_enable_unlocked(clk); | ||
179 | mutex_unlock(&clocks_mutex); | ||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | EXPORT_SYMBOL(clk_enable); | ||
184 | |||
185 | void clk_disable(struct clk *clk) | ||
186 | { | ||
187 | mutex_lock(&clocks_mutex); | ||
188 | clk_disable_unlocked(clk); | ||
189 | mutex_unlock(&clocks_mutex); | ||
190 | } | ||
191 | |||
192 | EXPORT_SYMBOL(clk_disable); | ||
193 | |||
194 | unsigned long clk_get_rate(struct clk *clk) | ||
195 | { | ||
196 | return clk->rate; | ||
197 | } | ||
198 | |||
199 | EXPORT_SYMBOL(clk_get_rate); | ||
200 | |||
201 | struct clk *clk_get(struct device *dev, const char *id) | ||
202 | { | ||
203 | if (!strcmp(id, "enet0")) | ||
204 | return &clk_enet0; | ||
205 | if (!strcmp(id, "enet1")) | ||
206 | return &clk_enet1; | ||
207 | if (!strcmp(id, "ephy")) | ||
208 | return &clk_ephy; | ||
209 | if (!strcmp(id, "usbh")) | ||
210 | return &clk_usbh; | ||
211 | if (!strcmp(id, "spi")) | ||
212 | return &clk_spi; | ||
213 | if (!strcmp(id, "periph")) | ||
214 | return &clk_periph; | ||
215 | if (BCMCPU_IS_6358() && !strcmp(id, "pcm")) | ||
216 | return &clk_pcm; | ||
217 | return ERR_PTR(-ENOENT); | ||
218 | } | ||
219 | |||
220 | EXPORT_SYMBOL(clk_get); | ||
221 | |||
222 | void clk_put(struct clk *clk) | ||
223 | { | ||
224 | } | ||
225 | |||
226 | EXPORT_SYMBOL(clk_put); | ||