diff options
author | Dmitriy Taychenachev <dimichxp@gmail.com> | 2009-07-31 07:29:22 -0400 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2009-08-14 06:40:46 -0400 |
commit | fd6ac7bb9d671d36fd7536c68fde977d197756ab (patch) | |
tree | 4c1993ee4079a55c6d621b46dba4826b92e3c028 /arch/arm/mach-mxc91231/clock.c | |
parent | 8e5be212cba6675dc363a224ce4a98bb07039b4b (diff) |
MXC: add basic MXC91231 support
Signed-off-by: Dmitriy Taychenachev <dimichxp@gmail.com>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'arch/arm/mach-mxc91231/clock.c')
-rw-r--r-- | arch/arm/mach-mxc91231/clock.c | 642 |
1 files changed, 642 insertions, 0 deletions
diff --git a/arch/arm/mach-mxc91231/clock.c b/arch/arm/mach-mxc91231/clock.c new file mode 100644 index 000000000000..ecfa37fef8ad --- /dev/null +++ b/arch/arm/mach-mxc91231/clock.c | |||
@@ -0,0 +1,642 @@ | |||
1 | #include <linux/clk.h> | ||
2 | #include <linux/kernel.h> | ||
3 | #include <linux/init.h> | ||
4 | #include <linux/io.h> | ||
5 | |||
6 | #include <mach/clock.h> | ||
7 | #include <mach/hardware.h> | ||
8 | #include <mach/common.h> | ||
9 | |||
10 | #include <asm/clkdev.h> | ||
11 | #include <asm/bug.h> | ||
12 | #include <asm/div64.h> | ||
13 | |||
14 | #include "crm_regs.h" | ||
15 | |||
16 | #define CRM_SMALL_DIVIDER(base, name) \ | ||
17 | crm_small_divider(base, \ | ||
18 | base ## _ ## name ## _OFFSET, \ | ||
19 | base ## _ ## name ## _MASK) | ||
20 | #define CRM_1DIVIDER(base, name) \ | ||
21 | crm_divider(base, \ | ||
22 | base ## _ ## name ## _OFFSET, \ | ||
23 | base ## _ ## name ## _MASK, 1) | ||
24 | #define CRM_16DIVIDER(base, name) \ | ||
25 | crm_divider(base, \ | ||
26 | base ## _ ## name ## _OFFSET, \ | ||
27 | base ## _ ## name ## _MASK, 16) | ||
28 | |||
29 | static u32 crm_small_divider(void __iomem *reg, u8 offset, u32 mask) | ||
30 | { | ||
31 | static const u32 crm_small_dividers[] = { | ||
32 | 2, 3, 4, 5, 6, 8, 10, 12 | ||
33 | }; | ||
34 | u8 idx; | ||
35 | |||
36 | idx = (__raw_readl(reg) & mask) >> offset; | ||
37 | if (idx > 7) | ||
38 | return 1; | ||
39 | |||
40 | return crm_small_dividers[idx]; | ||
41 | } | ||
42 | |||
43 | static u32 crm_divider(void __iomem *reg, u8 offset, u32 mask, u32 z) | ||
44 | { | ||
45 | u32 div; | ||
46 | div = (__raw_readl(reg) & mask) >> offset; | ||
47 | return div ? div : z; | ||
48 | } | ||
49 | |||
50 | static int _clk_1bit_enable(struct clk *clk) | ||
51 | { | ||
52 | u32 reg; | ||
53 | |||
54 | reg = __raw_readl(clk->enable_reg); | ||
55 | reg |= 1 << clk->enable_shift; | ||
56 | __raw_writel(reg, clk->enable_reg); | ||
57 | |||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | static void _clk_1bit_disable(struct clk *clk) | ||
62 | { | ||
63 | u32 reg; | ||
64 | |||
65 | reg = __raw_readl(clk->enable_reg); | ||
66 | reg &= ~(1 << clk->enable_shift); | ||
67 | __raw_writel(reg, clk->enable_reg); | ||
68 | } | ||
69 | |||
70 | static int _clk_3bit_enable(struct clk *clk) | ||
71 | { | ||
72 | u32 reg; | ||
73 | |||
74 | reg = __raw_readl(clk->enable_reg); | ||
75 | reg |= 0x7 << clk->enable_shift; | ||
76 | __raw_writel(reg, clk->enable_reg); | ||
77 | |||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | static void _clk_3bit_disable(struct clk *clk) | ||
82 | { | ||
83 | u32 reg; | ||
84 | |||
85 | reg = __raw_readl(clk->enable_reg); | ||
86 | reg &= ~(0x7 << clk->enable_shift); | ||
87 | __raw_writel(reg, clk->enable_reg); | ||
88 | } | ||
89 | |||
90 | static unsigned long ckih_rate; | ||
91 | |||
92 | static unsigned long clk_ckih_get_rate(struct clk *clk) | ||
93 | { | ||
94 | return ckih_rate; | ||
95 | } | ||
96 | |||
97 | static struct clk ckih_clk = { | ||
98 | .get_rate = clk_ckih_get_rate, | ||
99 | }; | ||
100 | |||
101 | static unsigned long clk_ckih_x2_get_rate(struct clk *clk) | ||
102 | { | ||
103 | return 2 * clk_get_rate(clk->parent); | ||
104 | } | ||
105 | |||
106 | static struct clk ckih_x2_clk = { | ||
107 | .parent = &ckih_clk, | ||
108 | .get_rate = clk_ckih_x2_get_rate, | ||
109 | }; | ||
110 | |||
111 | static unsigned long clk_ckil_get_rate(struct clk *clk) | ||
112 | { | ||
113 | return CKIL_CLK_FREQ; | ||
114 | } | ||
115 | |||
116 | static struct clk ckil_clk = { | ||
117 | .get_rate = clk_ckil_get_rate, | ||
118 | }; | ||
119 | |||
120 | /* plls stuff */ | ||
121 | static struct clk mcu_pll_clk; | ||
122 | static struct clk dsp_pll_clk; | ||
123 | static struct clk usb_pll_clk; | ||
124 | |||
125 | static struct clk *pll_clk(u8 sel) | ||
126 | { | ||
127 | switch (sel) { | ||
128 | case 0: | ||
129 | return &mcu_pll_clk; | ||
130 | case 1: | ||
131 | return &dsp_pll_clk; | ||
132 | case 2: | ||
133 | return &usb_pll_clk; | ||
134 | } | ||
135 | BUG(); | ||
136 | } | ||
137 | |||
138 | static void __iomem *pll_base(struct clk *clk) | ||
139 | { | ||
140 | if (clk == &mcu_pll_clk) | ||
141 | return MXC_PLL0_BASE; | ||
142 | else if (clk == &dsp_pll_clk) | ||
143 | return MXC_PLL1_BASE; | ||
144 | else if (clk == &usb_pll_clk) | ||
145 | return MXC_PLL2_BASE; | ||
146 | BUG(); | ||
147 | } | ||
148 | |||
149 | static unsigned long clk_pll_get_rate(struct clk *clk) | ||
150 | { | ||
151 | const void __iomem *pllbase; | ||
152 | unsigned long dp_op, dp_mfd, dp_mfn, pll_hfsm, ref_clk, mfi; | ||
153 | long mfn, mfn_abs, mfd, pdf; | ||
154 | s64 temp; | ||
155 | pllbase = pll_base(clk); | ||
156 | |||
157 | pll_hfsm = __raw_readl(pllbase + MXC_PLL_DP_CTL) & MXC_PLL_DP_CTL_HFSM; | ||
158 | if (pll_hfsm == 0) { | ||
159 | dp_op = __raw_readl(pllbase + MXC_PLL_DP_OP); | ||
160 | dp_mfd = __raw_readl(pllbase + MXC_PLL_DP_MFD); | ||
161 | dp_mfn = __raw_readl(pllbase + MXC_PLL_DP_MFN); | ||
162 | } else { | ||
163 | dp_op = __raw_readl(pllbase + MXC_PLL_DP_HFS_OP); | ||
164 | dp_mfd = __raw_readl(pllbase + MXC_PLL_DP_HFS_MFD); | ||
165 | dp_mfn = __raw_readl(pllbase + MXC_PLL_DP_HFS_MFN); | ||
166 | } | ||
167 | |||
168 | pdf = dp_op & MXC_PLL_DP_OP_PDF_MASK; | ||
169 | mfi = (dp_op >> MXC_PLL_DP_OP_MFI_OFFSET) & MXC_PLL_DP_OP_PDF_MASK; | ||
170 | mfi = (mfi <= 5) ? 5 : mfi; | ||
171 | mfd = dp_mfd & MXC_PLL_DP_MFD_MASK; | ||
172 | mfn = dp_mfn & MXC_PLL_DP_MFN_MASK; | ||
173 | mfn = (mfn <= 0x4000000) ? mfn : (mfn - 0x10000000); | ||
174 | |||
175 | if (mfn < 0) | ||
176 | mfn_abs = -mfn; | ||
177 | else | ||
178 | mfn_abs = mfn; | ||
179 | |||
180 | /* XXX: actually this asumes that ckih is fed to pll, but spec says | ||
181 | * that ckih_x2 is also possible. need to check this out. | ||
182 | */ | ||
183 | ref_clk = clk_get_rate(&ckih_clk); | ||
184 | |||
185 | ref_clk *= 2; | ||
186 | ref_clk /= pdf + 1; | ||
187 | |||
188 | temp = (u64) ref_clk * mfn_abs; | ||
189 | do_div(temp, mfd); | ||
190 | if (mfn < 0) | ||
191 | temp = -temp; | ||
192 | temp += ref_clk * mfi; | ||
193 | |||
194 | return temp; | ||
195 | } | ||
196 | |||
197 | static int clk_pll_enable(struct clk *clk) | ||
198 | { | ||
199 | void __iomem *ctl; | ||
200 | u32 reg; | ||
201 | |||
202 | ctl = pll_base(clk); | ||
203 | reg = __raw_readl(ctl); | ||
204 | reg |= (MXC_PLL_DP_CTL_RST | MXC_PLL_DP_CTL_UPEN); | ||
205 | __raw_writel(reg, ctl); | ||
206 | do { | ||
207 | reg = __raw_readl(ctl); | ||
208 | } while ((reg & MXC_PLL_DP_CTL_LRF) != MXC_PLL_DP_CTL_LRF); | ||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | static void clk_pll_disable(struct clk *clk) | ||
213 | { | ||
214 | void __iomem *ctl; | ||
215 | u32 reg; | ||
216 | |||
217 | ctl = pll_base(clk); | ||
218 | reg = __raw_readl(ctl); | ||
219 | reg &= ~(MXC_PLL_DP_CTL_RST | MXC_PLL_DP_CTL_UPEN); | ||
220 | __raw_writel(reg, ctl); | ||
221 | } | ||
222 | |||
223 | static struct clk mcu_pll_clk = { | ||
224 | .parent = &ckih_clk, | ||
225 | .get_rate = clk_pll_get_rate, | ||
226 | .enable = clk_pll_enable, | ||
227 | .disable = clk_pll_disable, | ||
228 | }; | ||
229 | |||
230 | static struct clk dsp_pll_clk = { | ||
231 | .parent = &ckih_clk, | ||
232 | .get_rate = clk_pll_get_rate, | ||
233 | .enable = clk_pll_enable, | ||
234 | .disable = clk_pll_disable, | ||
235 | }; | ||
236 | |||
237 | static struct clk usb_pll_clk = { | ||
238 | .parent = &ckih_clk, | ||
239 | .get_rate = clk_pll_get_rate, | ||
240 | .enable = clk_pll_enable, | ||
241 | .disable = clk_pll_disable, | ||
242 | }; | ||
243 | /* plls stuff end */ | ||
244 | |||
245 | /* ap_ref_clk stuff */ | ||
246 | static struct clk ap_ref_clk; | ||
247 | |||
248 | static unsigned long clk_ap_ref_get_rate(struct clk *clk) | ||
249 | { | ||
250 | u32 ascsr, acsr; | ||
251 | u8 ap_pat_ref_div_2, ap_isel, acs, ads; | ||
252 | |||
253 | ascsr = __raw_readl(MXC_CRMAP_ASCSR); | ||
254 | acsr = __raw_readl(MXC_CRMAP_ACSR); | ||
255 | |||
256 | /* 0 for ckih, 1 for ckih*2 */ | ||
257 | ap_isel = ascsr & MXC_CRMAP_ASCSR_APISEL; | ||
258 | /* reg divider */ | ||
259 | ap_pat_ref_div_2 = (ascsr >> MXC_CRMAP_ASCSR_AP_PATDIV2_OFFSET) & 0x1; | ||
260 | /* undocumented, 1 for disabling divider */ | ||
261 | ads = (acsr >> MXC_CRMAP_ACSR_ADS_OFFSET) & 0x1; | ||
262 | /* 0 for pat_ref, 1 for divider out */ | ||
263 | acs = acsr & MXC_CRMAP_ACSR_ACS; | ||
264 | |||
265 | if (acs & !ads) | ||
266 | /* use divided clock */ | ||
267 | return clk_get_rate(clk->parent) / (ap_pat_ref_div_2 ? 2 : 1); | ||
268 | |||
269 | return clk_get_rate(clk->parent) * (ap_isel ? 2 : 1); | ||
270 | } | ||
271 | |||
272 | static struct clk ap_ref_clk = { | ||
273 | .parent = &ckih_clk, | ||
274 | .get_rate = clk_ap_ref_get_rate, | ||
275 | }; | ||
276 | /* ap_ref_clk stuff end */ | ||
277 | |||
278 | /* ap_pre_dfs_clk stuff */ | ||
279 | static struct clk ap_pre_dfs_clk; | ||
280 | |||
281 | static unsigned long clk_ap_pre_dfs_get_rate(struct clk *clk) | ||
282 | { | ||
283 | u32 acsr, ascsr; | ||
284 | |||
285 | acsr = __raw_readl(MXC_CRMAP_ACSR); | ||
286 | ascsr = __raw_readl(MXC_CRMAP_ASCSR); | ||
287 | |||
288 | if (acsr & MXC_CRMAP_ACSR_ACS) { | ||
289 | u8 sel; | ||
290 | sel = (ascsr & MXC_CRMAP_ASCSR_APSEL_MASK) >> | ||
291 | MXC_CRMAP_ASCSR_APSEL_OFFSET; | ||
292 | return clk_get_rate(pll_clk(sel)) / | ||
293 | CRM_SMALL_DIVIDER(MXC_CRMAP_ACDR, ARMDIV); | ||
294 | } | ||
295 | return clk_get_rate(&ap_ref_clk); | ||
296 | } | ||
297 | |||
298 | static struct clk ap_pre_dfs_clk = { | ||
299 | .get_rate = clk_ap_pre_dfs_get_rate, | ||
300 | }; | ||
301 | /* ap_pre_dfs_clk stuff end */ | ||
302 | |||
303 | /* usb_clk stuff */ | ||
304 | static struct clk usb_clk; | ||
305 | |||
306 | static struct clk *clk_usb_parent(struct clk *clk) | ||
307 | { | ||
308 | u32 acsr, ascsr; | ||
309 | |||
310 | acsr = __raw_readl(MXC_CRMAP_ACSR); | ||
311 | ascsr = __raw_readl(MXC_CRMAP_ASCSR); | ||
312 | |||
313 | if (acsr & MXC_CRMAP_ACSR_ACS) { | ||
314 | u8 sel; | ||
315 | sel = (ascsr & MXC_CRMAP_ASCSR_USBSEL_MASK) >> | ||
316 | MXC_CRMAP_ASCSR_USBSEL_OFFSET; | ||
317 | return pll_clk(sel); | ||
318 | } | ||
319 | return &ap_ref_clk; | ||
320 | } | ||
321 | |||
322 | static unsigned long clk_usb_get_rate(struct clk *clk) | ||
323 | { | ||
324 | return clk_get_rate(clk->parent) / | ||
325 | CRM_SMALL_DIVIDER(MXC_CRMAP_ACDER2, USBDIV); | ||
326 | } | ||
327 | |||
328 | static struct clk usb_clk = { | ||
329 | .enable_reg = MXC_CRMAP_ACDER2, | ||
330 | .enable_shift = MXC_CRMAP_ACDER2_USBEN_OFFSET, | ||
331 | .get_rate = clk_usb_get_rate, | ||
332 | .enable = _clk_1bit_enable, | ||
333 | .disable = _clk_1bit_disable, | ||
334 | }; | ||
335 | /* usb_clk stuff end */ | ||
336 | |||
337 | static unsigned long clk_ipg_get_rate(struct clk *clk) | ||
338 | { | ||
339 | return clk_get_rate(clk->parent) / CRM_16DIVIDER(MXC_CRMAP_ACDR, IPDIV); | ||
340 | } | ||
341 | |||
342 | static unsigned long clk_ahb_get_rate(struct clk *clk) | ||
343 | { | ||
344 | return clk_get_rate(clk->parent) / | ||
345 | CRM_16DIVIDER(MXC_CRMAP_ACDR, AHBDIV); | ||
346 | } | ||
347 | |||
348 | static struct clk ipg_clk = { | ||
349 | .parent = &ap_pre_dfs_clk, | ||
350 | .get_rate = clk_ipg_get_rate, | ||
351 | }; | ||
352 | |||
353 | static struct clk ahb_clk = { | ||
354 | .parent = &ap_pre_dfs_clk, | ||
355 | .get_rate = clk_ahb_get_rate, | ||
356 | }; | ||
357 | |||
358 | /* perclk_clk stuff */ | ||
359 | static struct clk perclk_clk; | ||
360 | |||
361 | static unsigned long clk_perclk_get_rate(struct clk *clk) | ||
362 | { | ||
363 | u32 acder2; | ||
364 | |||
365 | acder2 = __raw_readl(MXC_CRMAP_ACDER2); | ||
366 | if (acder2 & MXC_CRMAP_ACDER2_BAUD_ISEL_MASK) | ||
367 | return 2 * clk_get_rate(clk->parent); | ||
368 | |||
369 | return clk_get_rate(clk->parent); | ||
370 | } | ||
371 | |||
372 | static struct clk perclk_clk = { | ||
373 | .parent = &ckih_clk, | ||
374 | .get_rate = clk_perclk_get_rate, | ||
375 | }; | ||
376 | /* perclk_clk stuff end */ | ||
377 | |||
378 | /* uart_clk stuff */ | ||
379 | static struct clk uart_clk[]; | ||
380 | |||
381 | static unsigned long clk_uart_get_rate(struct clk *clk) | ||
382 | { | ||
383 | u32 div; | ||
384 | |||
385 | switch (clk->id) { | ||
386 | case 0: | ||
387 | case 1: | ||
388 | div = CRM_SMALL_DIVIDER(MXC_CRMAP_ACDER2, BAUDDIV); | ||
389 | break; | ||
390 | case 2: | ||
391 | div = CRM_SMALL_DIVIDER(MXC_CRMAP_APRA, UART3DIV); | ||
392 | break; | ||
393 | default: | ||
394 | BUG(); | ||
395 | } | ||
396 | return clk_get_rate(clk->parent) / div; | ||
397 | } | ||
398 | |||
399 | static struct clk uart_clk[] = { | ||
400 | { | ||
401 | .id = 0, | ||
402 | .parent = &perclk_clk, | ||
403 | .enable_reg = MXC_CRMAP_APRA, | ||
404 | .enable_shift = MXC_CRMAP_APRA_UART1EN_OFFSET, | ||
405 | .get_rate = clk_uart_get_rate, | ||
406 | .enable = _clk_1bit_enable, | ||
407 | .disable = _clk_1bit_disable, | ||
408 | }, { | ||
409 | .id = 1, | ||
410 | .parent = &perclk_clk, | ||
411 | .enable_reg = MXC_CRMAP_APRA, | ||
412 | .enable_shift = MXC_CRMAP_APRA_UART2EN_OFFSET, | ||
413 | .get_rate = clk_uart_get_rate, | ||
414 | .enable = _clk_1bit_enable, | ||
415 | .disable = _clk_1bit_disable, | ||
416 | }, { | ||
417 | .id = 2, | ||
418 | .parent = &perclk_clk, | ||
419 | .enable_reg = MXC_CRMAP_APRA, | ||
420 | .enable_shift = MXC_CRMAP_APRA_UART3EN_OFFSET, | ||
421 | .get_rate = clk_uart_get_rate, | ||
422 | .enable = _clk_1bit_enable, | ||
423 | .disable = _clk_1bit_disable, | ||
424 | }, | ||
425 | }; | ||
426 | /* uart_clk stuff end */ | ||
427 | |||
428 | /* sdhc_clk stuff */ | ||
429 | static struct clk nfc_clk; | ||
430 | |||
431 | static unsigned long clk_nfc_get_rate(struct clk *clk) | ||
432 | { | ||
433 | return clk_get_rate(clk->parent) / | ||
434 | CRM_1DIVIDER(MXC_CRMAP_ACDER2, NFCDIV); | ||
435 | } | ||
436 | |||
437 | static struct clk nfc_clk = { | ||
438 | .parent = &ahb_clk, | ||
439 | .enable_reg = MXC_CRMAP_ACDER2, | ||
440 | .enable_shift = MXC_CRMAP_ACDER2_NFCEN_OFFSET, | ||
441 | .get_rate = clk_nfc_get_rate, | ||
442 | .enable = _clk_1bit_enable, | ||
443 | .disable = _clk_1bit_disable, | ||
444 | }; | ||
445 | /* sdhc_clk stuff end */ | ||
446 | |||
447 | /* sdhc_clk stuff */ | ||
448 | static struct clk sdhc_clk[]; | ||
449 | |||
450 | static struct clk *clk_sdhc_parent(struct clk *clk) | ||
451 | { | ||
452 | u32 aprb; | ||
453 | u8 sel; | ||
454 | u32 mask; | ||
455 | int offset; | ||
456 | |||
457 | aprb = __raw_readl(MXC_CRMAP_APRB); | ||
458 | |||
459 | switch (clk->id) { | ||
460 | case 0: | ||
461 | mask = MXC_CRMAP_APRB_SDHC1_ISEL_MASK; | ||
462 | offset = MXC_CRMAP_APRB_SDHC1_ISEL_OFFSET; | ||
463 | break; | ||
464 | case 1: | ||
465 | mask = MXC_CRMAP_APRB_SDHC2_ISEL_MASK; | ||
466 | offset = MXC_CRMAP_APRB_SDHC2_ISEL_OFFSET; | ||
467 | break; | ||
468 | default: | ||
469 | BUG(); | ||
470 | } | ||
471 | sel = (aprb & mask) >> offset; | ||
472 | |||
473 | switch (sel) { | ||
474 | case 0: | ||
475 | return &ckih_clk; | ||
476 | case 1: | ||
477 | return &ckih_x2_clk; | ||
478 | } | ||
479 | return &usb_clk; | ||
480 | } | ||
481 | |||
482 | static unsigned long clk_sdhc_get_rate(struct clk *clk) | ||
483 | { | ||
484 | u32 div; | ||
485 | |||
486 | switch (clk->id) { | ||
487 | case 0: | ||
488 | div = CRM_SMALL_DIVIDER(MXC_CRMAP_APRB, SDHC1_DIV); | ||
489 | break; | ||
490 | case 1: | ||
491 | div = CRM_SMALL_DIVIDER(MXC_CRMAP_APRB, SDHC2_DIV); | ||
492 | break; | ||
493 | default: | ||
494 | BUG(); | ||
495 | } | ||
496 | |||
497 | return clk_get_rate(clk->parent) / div; | ||
498 | } | ||
499 | |||
500 | static int clk_sdhc_enable(struct clk *clk) | ||
501 | { | ||
502 | u32 amlpmre1, aprb; | ||
503 | |||
504 | amlpmre1 = __raw_readl(MXC_CRMAP_AMLPMRE1); | ||
505 | aprb = __raw_readl(MXC_CRMAP_APRB); | ||
506 | switch (clk->id) { | ||
507 | case 0: | ||
508 | amlpmre1 |= (0x7 << MXC_CRMAP_AMLPMRE1_MLPME4_OFFSET); | ||
509 | aprb |= (0x1 << MXC_CRMAP_APRB_SDHC1EN_OFFSET); | ||
510 | break; | ||
511 | case 1: | ||
512 | amlpmre1 |= (0x7 << MXC_CRMAP_AMLPMRE1_MLPME5_OFFSET); | ||
513 | aprb |= (0x1 << MXC_CRMAP_APRB_SDHC2EN_OFFSET); | ||
514 | break; | ||
515 | } | ||
516 | __raw_writel(amlpmre1, MXC_CRMAP_AMLPMRE1); | ||
517 | __raw_writel(aprb, MXC_CRMAP_APRB); | ||
518 | return 0; | ||
519 | } | ||
520 | |||
521 | static void clk_sdhc_disable(struct clk *clk) | ||
522 | { | ||
523 | u32 amlpmre1, aprb; | ||
524 | |||
525 | amlpmre1 = __raw_readl(MXC_CRMAP_AMLPMRE1); | ||
526 | aprb = __raw_readl(MXC_CRMAP_APRB); | ||
527 | switch (clk->id) { | ||
528 | case 0: | ||
529 | amlpmre1 &= ~(0x7 << MXC_CRMAP_AMLPMRE1_MLPME4_OFFSET); | ||
530 | aprb &= ~(0x1 << MXC_CRMAP_APRB_SDHC1EN_OFFSET); | ||
531 | break; | ||
532 | case 1: | ||
533 | amlpmre1 &= ~(0x7 << MXC_CRMAP_AMLPMRE1_MLPME5_OFFSET); | ||
534 | aprb &= ~(0x1 << MXC_CRMAP_APRB_SDHC2EN_OFFSET); | ||
535 | break; | ||
536 | } | ||
537 | __raw_writel(amlpmre1, MXC_CRMAP_AMLPMRE1); | ||
538 | __raw_writel(aprb, MXC_CRMAP_APRB); | ||
539 | } | ||
540 | |||
541 | static struct clk sdhc_clk[] = { | ||
542 | { | ||
543 | .id = 0, | ||
544 | .get_rate = clk_sdhc_get_rate, | ||
545 | .enable = clk_sdhc_enable, | ||
546 | .disable = clk_sdhc_disable, | ||
547 | }, { | ||
548 | .id = 1, | ||
549 | .get_rate = clk_sdhc_get_rate, | ||
550 | .enable = clk_sdhc_enable, | ||
551 | .disable = clk_sdhc_disable, | ||
552 | }, | ||
553 | }; | ||
554 | /* sdhc_clk stuff end */ | ||
555 | |||
556 | /* wdog_clk stuff */ | ||
557 | static struct clk wdog_clk[] = { | ||
558 | { | ||
559 | .id = 0, | ||
560 | .parent = &ipg_clk, | ||
561 | .enable_reg = MXC_CRMAP_AMLPMRD, | ||
562 | .enable_shift = MXC_CRMAP_AMLPMRD_MLPMD7_OFFSET, | ||
563 | .enable = _clk_3bit_enable, | ||
564 | .disable = _clk_3bit_disable, | ||
565 | }, { | ||
566 | .id = 1, | ||
567 | .parent = &ipg_clk, | ||
568 | .enable_reg = MXC_CRMAP_AMLPMRD, | ||
569 | .enable_shift = MXC_CRMAP_AMLPMRD_MLPMD3_OFFSET, | ||
570 | .enable = _clk_3bit_enable, | ||
571 | .disable = _clk_3bit_disable, | ||
572 | }, | ||
573 | }; | ||
574 | /* wdog_clk stuff end */ | ||
575 | |||
576 | /* gpt_clk stuff */ | ||
577 | static struct clk gpt_clk = { | ||
578 | .parent = &ipg_clk, | ||
579 | .enable_reg = MXC_CRMAP_AMLPMRC, | ||
580 | .enable_shift = MXC_CRMAP_AMLPMRC_MLPMC4_OFFSET, | ||
581 | .enable = _clk_3bit_enable, | ||
582 | .disable = _clk_3bit_disable, | ||
583 | }; | ||
584 | /* gpt_clk stuff end */ | ||
585 | |||
586 | /* cspi_clk stuff */ | ||
587 | static struct clk cspi_clk[] = { | ||
588 | { | ||
589 | .id = 0, | ||
590 | .parent = &ipg_clk, | ||
591 | .enable_reg = MXC_CRMAP_AMLPMRE2, | ||
592 | .enable_shift = MXC_CRMAP_AMLPMRE2_MLPME0_OFFSET, | ||
593 | .enable = _clk_3bit_enable, | ||
594 | .disable = _clk_3bit_disable, | ||
595 | }, { | ||
596 | .id = 1, | ||
597 | .parent = &ipg_clk, | ||
598 | .enable_reg = MXC_CRMAP_AMLPMRE1, | ||
599 | .enable_shift = MXC_CRMAP_AMLPMRE1_MLPME6_OFFSET, | ||
600 | .enable = _clk_3bit_enable, | ||
601 | .disable = _clk_3bit_disable, | ||
602 | }, | ||
603 | }; | ||
604 | /* cspi_clk stuff end */ | ||
605 | |||
606 | #define _REGISTER_CLOCK(d, n, c) \ | ||
607 | { \ | ||
608 | .dev_id = d, \ | ||
609 | .con_id = n, \ | ||
610 | .clk = &c, \ | ||
611 | }, | ||
612 | |||
613 | static struct clk_lookup lookups[] = { | ||
614 | _REGISTER_CLOCK("imx-uart.0", NULL, uart_clk[0]) | ||
615 | _REGISTER_CLOCK("imx-uart.1", NULL, uart_clk[1]) | ||
616 | _REGISTER_CLOCK("imx-uart.2", NULL, uart_clk[2]) | ||
617 | _REGISTER_CLOCK("mxc-mmc.0", NULL, sdhc_clk[0]) | ||
618 | _REGISTER_CLOCK("mxc-mmc.1", NULL, sdhc_clk[1]) | ||
619 | _REGISTER_CLOCK("mxc-wdt.0", NULL, wdog_clk[0]) | ||
620 | _REGISTER_CLOCK("spi_imx.0", NULL, cspi_clk[0]) | ||
621 | _REGISTER_CLOCK("spi_imx.1", NULL, cspi_clk[1]) | ||
622 | }; | ||
623 | |||
624 | int __init mxc91231_clocks_init(unsigned long fref) | ||
625 | { | ||
626 | void __iomem *gpt_base; | ||
627 | int i; | ||
628 | |||
629 | ckih_rate = fref; | ||
630 | |||
631 | usb_clk.parent = clk_usb_parent(&usb_clk); | ||
632 | sdhc_clk[0].parent = clk_sdhc_parent(&sdhc_clk[0]); | ||
633 | sdhc_clk[1].parent = clk_sdhc_parent(&sdhc_clk[1]); | ||
634 | |||
635 | for (i = 0; i < ARRAY_SIZE(lookups); i++) | ||
636 | clkdev_add(&lookups[i]); | ||
637 | |||
638 | gpt_base = MXC91231_IO_ADDRESS(MXC91231_GPT1_BASE_ADDR); | ||
639 | mxc_timer_init(&gpt_clk, gpt_base, MXC91231_INT_GPT); | ||
640 | |||
641 | return 0; | ||
642 | } | ||