diff options
author | Robert Jarzmik <robert.jarzmik@free.fr> | 2014-07-30 16:51:02 -0400 |
---|---|---|
committer | Mike Turquette <mturquette@linaro.org> | 2014-09-30 15:31:31 -0400 |
commit | d40670dc616936ed12335b9408087c9923939f1f (patch) | |
tree | 7f3f71e924bd77bb35d76758ed681086cbb98728 /drivers/clk/pxa/clk-pxa27x.c | |
parent | 108f303f0ed92549b061e08a18361ad4bd540b27 (diff) |
clk: add pxa27x clock drivers
Move pxa27x clock drivers from arch/arm/mach-pxa to driver/clk.
In the move :
- convert to new clock framework legacy clocks
- provide clocks as before for platform data based boards
- provide clocks through devicetree
Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
Signed-off-by: Mike Turquette <mturquette@linaro.org>
Diffstat (limited to 'drivers/clk/pxa/clk-pxa27x.c')
-rw-r--r-- | drivers/clk/pxa/clk-pxa27x.c | 370 |
1 files changed, 370 insertions, 0 deletions
diff --git a/drivers/clk/pxa/clk-pxa27x.c b/drivers/clk/pxa/clk-pxa27x.c new file mode 100644 index 000000000000..b345cc791e5d --- /dev/null +++ b/drivers/clk/pxa/clk-pxa27x.c | |||
@@ -0,0 +1,370 @@ | |||
1 | /* | ||
2 | * Marvell PXA27x family clocks | ||
3 | * | ||
4 | * Copyright (C) 2014 Robert Jarzmik | ||
5 | * | ||
6 | * Heavily inspired from former arch/arm/mach-pxa/clock.c. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; version 2 of the License. | ||
11 | * | ||
12 | */ | ||
13 | #include <linux/clk-provider.h> | ||
14 | #include <mach/pxa2xx-regs.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/clk.h> | ||
17 | #include <linux/clkdev.h> | ||
18 | #include <linux/of.h> | ||
19 | |||
20 | #include <dt-bindings/clock/pxa-clock.h> | ||
21 | #include "clk-pxa.h" | ||
22 | |||
23 | #define KHz 1000 | ||
24 | #define MHz (1000 * 1000) | ||
25 | |||
26 | enum { | ||
27 | PXA_CORE_13Mhz = 0, | ||
28 | PXA_CORE_RUN, | ||
29 | PXA_CORE_TURBO, | ||
30 | }; | ||
31 | |||
32 | enum { | ||
33 | PXA_BUS_13Mhz = 0, | ||
34 | PXA_BUS_RUN, | ||
35 | }; | ||
36 | |||
37 | enum { | ||
38 | PXA_LCD_13Mhz = 0, | ||
39 | PXA_LCD_RUN, | ||
40 | }; | ||
41 | |||
42 | enum { | ||
43 | PXA_MEM_13Mhz = 0, | ||
44 | PXA_MEM_SYSTEM_BUS, | ||
45 | PXA_MEM_RUN, | ||
46 | }; | ||
47 | |||
48 | static const char * const get_freq_khz[] = { | ||
49 | "core", "run", "cpll", "memory", | ||
50 | "system_bus" | ||
51 | }; | ||
52 | |||
53 | /* | ||
54 | * Get the clock frequency as reflected by CCSR and the turbo flag. | ||
55 | * We assume these values have been applied via a fcs. | ||
56 | * If info is not 0 we also display the current settings. | ||
57 | */ | ||
58 | unsigned int pxa27x_get_clk_frequency_khz(int info) | ||
59 | { | ||
60 | struct clk *clk; | ||
61 | unsigned long clks[5]; | ||
62 | int i; | ||
63 | |||
64 | for (i = 0; i < 5; i++) { | ||
65 | clk = clk_get(NULL, get_freq_khz[i]); | ||
66 | if (IS_ERR(clk)) { | ||
67 | clks[i] = 0; | ||
68 | } else { | ||
69 | clks[i] = clk_get_rate(clk); | ||
70 | clk_put(clk); | ||
71 | } | ||
72 | } | ||
73 | if (info) { | ||
74 | pr_info("Run Mode clock: %ld.%02ldMHz\n", | ||
75 | clks[1] / 1000000, (clks[1] % 1000000) / 10000); | ||
76 | pr_info("Turbo Mode clock: %ld.%02ldMHz\n", | ||
77 | clks[2] / 1000000, (clks[2] % 1000000) / 10000); | ||
78 | pr_info("Memory clock: %ld.%02ldMHz\n", | ||
79 | clks[3] / 1000000, (clks[3] % 1000000) / 10000); | ||
80 | pr_info("System bus clock: %ld.%02ldMHz\n", | ||
81 | clks[4] / 1000000, (clks[4] % 1000000) / 10000); | ||
82 | } | ||
83 | return (unsigned int)clks[0]; | ||
84 | } | ||
85 | |||
86 | bool pxa27x_is_ppll_disabled(void) | ||
87 | { | ||
88 | unsigned long ccsr = CCSR; | ||
89 | |||
90 | return ccsr & (1 << CCCR_PPDIS_BIT); | ||
91 | } | ||
92 | |||
93 | #define PXA27X_CKEN(dev_id, con_id, parents, mult_hp, div_hp, \ | ||
94 | bit, is_lp, flags) \ | ||
95 | PXA_CKEN(dev_id, con_id, bit, parents, 1, 1, mult_hp, div_hp, \ | ||
96 | is_lp, &CKEN, CKEN_ ## bit, flags) | ||
97 | #define PXA27X_PBUS_CKEN(dev_id, con_id, bit, mult_hp, div_hp, delay) \ | ||
98 | PXA27X_CKEN(dev_id, con_id, pxa27x_pbus_parents, mult_hp, \ | ||
99 | div_hp, bit, pxa27x_is_ppll_disabled, 0) | ||
100 | |||
101 | PARENTS(pxa27x_pbus) = { "osc_13mhz", "ppll_312mhz" }; | ||
102 | PARENTS(pxa27x_sbus) = { "system_bus", "system_bus" }; | ||
103 | PARENTS(pxa27x_32Mhz_bus) = { "osc_32_768khz", "osc_32_768khz" }; | ||
104 | PARENTS(pxa27x_lcd_bus) = { "lcd_base", "lcd_base" }; | ||
105 | PARENTS(pxa27x_membus) = { "lcd_base", "lcd_base" }; | ||
106 | |||
107 | #define PXA27X_CKEN_1RATE(dev_id, con_id, bit, parents, delay) \ | ||
108 | PXA_CKEN_1RATE(dev_id, con_id, bit, parents, \ | ||
109 | &CKEN, CKEN_ ## bit, 0) | ||
110 | #define PXA27X_CKEN_1RATE_AO(dev_id, con_id, bit, parents, delay) \ | ||
111 | PXA_CKEN_1RATE(dev_id, con_id, bit, parents, \ | ||
112 | &CKEN, CKEN_ ## bit, CLK_IGNORE_UNUSED) | ||
113 | |||
114 | static struct pxa_clk_cken pxa27x_clocks[] = { | ||
115 | PXA27X_PBUS_CKEN("pxa2xx-uart.0", NULL, FFUART, 2, 42, 1), | ||
116 | PXA27X_PBUS_CKEN("pxa2xx-uart.1", NULL, BTUART, 2, 42, 1), | ||
117 | PXA27X_PBUS_CKEN("pxa2xx-uart.2", NULL, STUART, 2, 42, 1), | ||
118 | PXA27X_PBUS_CKEN("pxa2xx-i2s", NULL, I2S, 2, 51, 0), | ||
119 | PXA27X_PBUS_CKEN("pxa2xx-i2c.0", NULL, I2C, 2, 19, 0), | ||
120 | PXA27X_PBUS_CKEN("pxa27x-udc", NULL, USB, 2, 13, 5), | ||
121 | PXA27X_PBUS_CKEN("pxa2xx-mci.0", NULL, MMC, 2, 32, 0), | ||
122 | PXA27X_PBUS_CKEN("pxa2xx-ir", "FICPCLK", FICP, 2, 13, 0), | ||
123 | PXA27X_PBUS_CKEN("pxa27x-ohci", NULL, USBHOST, 2, 13, 0), | ||
124 | PXA27X_PBUS_CKEN("pxa2xx-i2c.1", NULL, PWRI2C, 1, 24, 0), | ||
125 | PXA27X_PBUS_CKEN("pxa27x-ssp.0", NULL, SSP1, 1, 24, 0), | ||
126 | PXA27X_PBUS_CKEN("pxa27x-ssp.1", NULL, SSP2, 1, 24, 0), | ||
127 | PXA27X_PBUS_CKEN("pxa27x-ssp.2", NULL, SSP3, 1, 24, 0), | ||
128 | PXA27X_PBUS_CKEN("pxa27x-pwm.0", NULL, PWM0, 1, 24, 0), | ||
129 | PXA27X_PBUS_CKEN("pxa27x-pwm.1", NULL, PWM1, 1, 24, 0), | ||
130 | PXA27X_PBUS_CKEN(NULL, "MSLCLK", MSL, 2, 13, 0), | ||
131 | PXA27X_PBUS_CKEN(NULL, "USIMCLK", USIM, 2, 13, 0), | ||
132 | PXA27X_PBUS_CKEN(NULL, "MSTKCLK", MEMSTK, 2, 32, 0), | ||
133 | PXA27X_PBUS_CKEN(NULL, "AC97CLK", AC97, 1, 1, 0), | ||
134 | PXA27X_PBUS_CKEN(NULL, "AC97CONFCLK", AC97CONF, 1, 1, 0), | ||
135 | PXA27X_PBUS_CKEN(NULL, "OSTIMER0", OSTIMER, 1, 96, 0), | ||
136 | |||
137 | PXA27X_CKEN_1RATE("pxa27x-keypad", NULL, KEYPAD, | ||
138 | pxa27x_32Mhz_bus_parents, 0), | ||
139 | PXA27X_CKEN_1RATE(NULL, "IMCLK", IM, pxa27x_sbus_parents, 0), | ||
140 | PXA27X_CKEN_1RATE("pxa2xx-fb", NULL, LCD, pxa27x_lcd_bus_parents, 0), | ||
141 | PXA27X_CKEN_1RATE("pxa27x-camera.0", NULL, CAMERA, | ||
142 | pxa27x_lcd_bus_parents, 0), | ||
143 | PXA27X_CKEN_1RATE_AO("pxa2xx-pcmcia", NULL, MEMC, | ||
144 | pxa27x_membus_parents, 0), | ||
145 | |||
146 | }; | ||
147 | |||
148 | static unsigned long clk_pxa27x_cpll_get_rate(struct clk_hw *hw, | ||
149 | unsigned long parent_rate) | ||
150 | { | ||
151 | unsigned long clkcfg; | ||
152 | unsigned int t, ht; | ||
153 | unsigned int l, L, n2, N; | ||
154 | unsigned long ccsr = CCSR; | ||
155 | |||
156 | asm("mrc\tp14, 0, %0, c6, c0, 0" : "=r" (clkcfg)); | ||
157 | t = clkcfg & (1 << 0); | ||
158 | ht = clkcfg & (1 << 2); | ||
159 | |||
160 | l = ccsr & CCSR_L_MASK; | ||
161 | n2 = (ccsr & CCSR_N2_MASK) >> CCSR_N2_SHIFT; | ||
162 | L = l * parent_rate; | ||
163 | N = (L * n2) / 2; | ||
164 | |||
165 | return t ? N : L; | ||
166 | } | ||
167 | PARENTS(clk_pxa27x_cpll) = { "osc_13mhz" }; | ||
168 | RATE_RO_OPS(clk_pxa27x_cpll, "cpll"); | ||
169 | |||
170 | static unsigned long clk_pxa27x_lcd_base_get_rate(struct clk_hw *hw, | ||
171 | unsigned long parent_rate) | ||
172 | { | ||
173 | unsigned int l, osc_forced; | ||
174 | unsigned long ccsr = CCSR; | ||
175 | unsigned long cccr = CCCR; | ||
176 | |||
177 | l = ccsr & CCSR_L_MASK; | ||
178 | osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); | ||
179 | if (osc_forced) { | ||
180 | if (cccr & (1 << CCCR_LCD_26_BIT)) | ||
181 | return parent_rate * 2; | ||
182 | else | ||
183 | return parent_rate; | ||
184 | } | ||
185 | |||
186 | if (l <= 7) | ||
187 | return parent_rate; | ||
188 | if (l <= 16) | ||
189 | return parent_rate / 2; | ||
190 | return parent_rate / 4; | ||
191 | } | ||
192 | |||
193 | static u8 clk_pxa27x_lcd_base_get_parent(struct clk_hw *hw) | ||
194 | { | ||
195 | unsigned int osc_forced; | ||
196 | unsigned long ccsr = CCSR; | ||
197 | |||
198 | osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); | ||
199 | if (osc_forced) | ||
200 | return PXA_LCD_13Mhz; | ||
201 | else | ||
202 | return PXA_LCD_RUN; | ||
203 | } | ||
204 | |||
205 | PARENTS(clk_pxa27x_lcd_base) = { "osc_13mhz", "run" }; | ||
206 | MUX_RO_RATE_RO_OPS(clk_pxa27x_lcd_base, "lcd_base"); | ||
207 | |||
208 | static void __init pxa27x_register_plls(void) | ||
209 | { | ||
210 | clk_register_fixed_rate(NULL, "osc_13mhz", NULL, | ||
211 | CLK_GET_RATE_NOCACHE | CLK_IS_ROOT, | ||
212 | 13 * MHz); | ||
213 | clk_register_fixed_rate(NULL, "osc_32_768khz", NULL, | ||
214 | CLK_GET_RATE_NOCACHE | CLK_IS_ROOT, | ||
215 | 32768 * KHz); | ||
216 | clk_register_fixed_rate(NULL, "clk_dummy", NULL, CLK_IS_ROOT, 0); | ||
217 | clk_register_fixed_factor(NULL, "ppll_312mhz", "osc_13mhz", 0, 24, 1); | ||
218 | } | ||
219 | |||
220 | static unsigned long clk_pxa27x_core_get_rate(struct clk_hw *hw, | ||
221 | unsigned long parent_rate) | ||
222 | { | ||
223 | unsigned long clkcfg; | ||
224 | unsigned int t, ht, b, osc_forced; | ||
225 | unsigned long ccsr = CCSR; | ||
226 | |||
227 | osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); | ||
228 | asm("mrc\tp14, 0, %0, c6, c0, 0" : "=r" (clkcfg)); | ||
229 | t = clkcfg & (1 << 0); | ||
230 | ht = clkcfg & (1 << 2); | ||
231 | b = clkcfg & (1 << 3); | ||
232 | |||
233 | if (osc_forced) | ||
234 | return parent_rate; | ||
235 | if (ht) | ||
236 | return parent_rate / 2; | ||
237 | else | ||
238 | return parent_rate; | ||
239 | } | ||
240 | |||
241 | static u8 clk_pxa27x_core_get_parent(struct clk_hw *hw) | ||
242 | { | ||
243 | unsigned long clkcfg; | ||
244 | unsigned int t, ht, b, osc_forced; | ||
245 | unsigned long ccsr = CCSR; | ||
246 | |||
247 | osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); | ||
248 | if (osc_forced) | ||
249 | return PXA_CORE_13Mhz; | ||
250 | |||
251 | asm("mrc\tp14, 0, %0, c6, c0, 0" : "=r" (clkcfg)); | ||
252 | t = clkcfg & (1 << 0); | ||
253 | ht = clkcfg & (1 << 2); | ||
254 | b = clkcfg & (1 << 3); | ||
255 | |||
256 | if (ht || t) | ||
257 | return PXA_CORE_TURBO; | ||
258 | return PXA_CORE_RUN; | ||
259 | } | ||
260 | PARENTS(clk_pxa27x_core) = { "osc_13mhz", "run", "cpll" }; | ||
261 | MUX_RO_RATE_RO_OPS(clk_pxa27x_core, "core"); | ||
262 | |||
263 | static unsigned long clk_pxa27x_run_get_rate(struct clk_hw *hw, | ||
264 | unsigned long parent_rate) | ||
265 | { | ||
266 | unsigned long ccsr = CCSR; | ||
267 | unsigned int n2 = (ccsr & CCSR_N2_MASK) >> CCSR_N2_SHIFT; | ||
268 | |||
269 | return (parent_rate / n2) * 2; | ||
270 | } | ||
271 | PARENTS(clk_pxa27x_run) = { "cpll" }; | ||
272 | RATE_RO_OPS(clk_pxa27x_run, "run"); | ||
273 | |||
274 | static void __init pxa27x_register_core(void) | ||
275 | { | ||
276 | clk_register_clk_pxa27x_cpll(); | ||
277 | clk_register_clk_pxa27x_run(); | ||
278 | |||
279 | clkdev_pxa_register(CLK_CORE, "core", NULL, | ||
280 | clk_register_clk_pxa27x_core()); | ||
281 | } | ||
282 | |||
283 | static unsigned long clk_pxa27x_system_bus_get_rate(struct clk_hw *hw, | ||
284 | unsigned long parent_rate) | ||
285 | { | ||
286 | unsigned long clkcfg; | ||
287 | unsigned int b, osc_forced; | ||
288 | unsigned long ccsr = CCSR; | ||
289 | |||
290 | osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); | ||
291 | asm("mrc\tp14, 0, %0, c6, c0, 0" : "=r" (clkcfg)); | ||
292 | b = clkcfg & (1 << 3); | ||
293 | |||
294 | if (osc_forced) | ||
295 | return parent_rate; | ||
296 | if (b) | ||
297 | return parent_rate / 2; | ||
298 | else | ||
299 | return parent_rate; | ||
300 | } | ||
301 | |||
302 | static u8 clk_pxa27x_system_bus_get_parent(struct clk_hw *hw) | ||
303 | { | ||
304 | unsigned int osc_forced; | ||
305 | unsigned long ccsr = CCSR; | ||
306 | |||
307 | osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); | ||
308 | if (osc_forced) | ||
309 | return PXA_BUS_13Mhz; | ||
310 | else | ||
311 | return PXA_BUS_RUN; | ||
312 | } | ||
313 | |||
314 | PARENTS(clk_pxa27x_system_bus) = { "osc_13mhz", "run" }; | ||
315 | MUX_RO_RATE_RO_OPS(clk_pxa27x_system_bus, "system_bus"); | ||
316 | |||
317 | static unsigned long clk_pxa27x_memory_get_rate(struct clk_hw *hw, | ||
318 | unsigned long parent_rate) | ||
319 | { | ||
320 | unsigned int a, l, osc_forced; | ||
321 | unsigned long cccr = CCCR; | ||
322 | unsigned long ccsr = CCSR; | ||
323 | |||
324 | osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); | ||
325 | a = cccr & CCCR_A_BIT; | ||
326 | l = ccsr & CCSR_L_MASK; | ||
327 | |||
328 | if (osc_forced || a) | ||
329 | return parent_rate; | ||
330 | if (l <= 10) | ||
331 | return parent_rate; | ||
332 | if (l <= 20) | ||
333 | return parent_rate / 2; | ||
334 | return parent_rate / 4; | ||
335 | } | ||
336 | |||
337 | static u8 clk_pxa27x_memory_get_parent(struct clk_hw *hw) | ||
338 | { | ||
339 | unsigned int osc_forced, a; | ||
340 | unsigned long cccr = CCCR; | ||
341 | unsigned long ccsr = CCSR; | ||
342 | |||
343 | osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); | ||
344 | a = cccr & CCCR_A_BIT; | ||
345 | if (osc_forced) | ||
346 | return PXA_MEM_13Mhz; | ||
347 | if (a) | ||
348 | return PXA_MEM_SYSTEM_BUS; | ||
349 | else | ||
350 | return PXA_MEM_RUN; | ||
351 | } | ||
352 | |||
353 | PARENTS(clk_pxa27x_memory) = { "osc_13mhz", "system_bus", "run" }; | ||
354 | MUX_RO_RATE_RO_OPS(clk_pxa27x_memory, "memory"); | ||
355 | |||
356 | static void __init pxa27x_base_clocks_init(void) | ||
357 | { | ||
358 | pxa27x_register_plls(); | ||
359 | pxa27x_register_core(); | ||
360 | clk_register_clk_pxa27x_system_bus(); | ||
361 | clk_register_clk_pxa27x_memory(); | ||
362 | clk_register_clk_pxa27x_lcd_base(); | ||
363 | } | ||
364 | |||
365 | static int __init pxa27x_clocks_init(void) | ||
366 | { | ||
367 | pxa27x_base_clocks_init(); | ||
368 | return clk_pxa_cken_init(pxa27x_clocks, ARRAY_SIZE(pxa27x_clocks)); | ||
369 | } | ||
370 | postcore_initcall(pxa27x_clocks_init); | ||