diff options
author | Robert Jarzmik <robert.jarzmik@free.fr> | 2014-11-11 09:53:25 -0500 |
---|---|---|
committer | Michael Turquette <mturquette@linaro.org> | 2014-11-17 14:20:55 -0500 |
commit | fe7710fae477f648773648ea0a05b079c5b66667 (patch) | |
tree | 84767a4506ac277adafde364df81bf22233dd2dd /drivers/clk | |
parent | 280da705802c7606e5b943f885390bbbf1d8049d (diff) |
clk: add pxa25x clock drivers
Move pxa25x 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 with clk-pxa-dt
This is the preliminary step in the conversion. The remaining steps are
:
- pxa3xx
- once PXA is fully converted to device tree, if that happens,
clk-pxa2* and clk-pxa3* should only hold the core clocks which cannot
be described in devicetree.
Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
Tested-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Signed-off-by: Michael Turquette <mturquette@linaro.org>
Diffstat (limited to 'drivers/clk')
-rw-r--r-- | drivers/clk/pxa/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/pxa/clk-pxa25x.c | 273 |
2 files changed, 274 insertions, 0 deletions
diff --git a/drivers/clk/pxa/Makefile b/drivers/clk/pxa/Makefile index 4ff2abcd500b..38e915344605 100644 --- a/drivers/clk/pxa/Makefile +++ b/drivers/clk/pxa/Makefile | |||
@@ -1,2 +1,3 @@ | |||
1 | obj-y += clk-pxa.o | 1 | obj-y += clk-pxa.o |
2 | obj-$(CONFIG_PXA25x) += clk-pxa25x.o | ||
2 | obj-$(CONFIG_PXA27x) += clk-pxa27x.o | 3 | obj-$(CONFIG_PXA27x) += clk-pxa27x.o |
diff --git a/drivers/clk/pxa/clk-pxa25x.c b/drivers/clk/pxa/clk-pxa25x.c new file mode 100644 index 000000000000..6cd88d963a7f --- /dev/null +++ b/drivers/clk/pxa/clk-pxa25x.c | |||
@@ -0,0 +1,273 @@ | |||
1 | /* | ||
2 | * Marvell PXA25x family clocks | ||
3 | * | ||
4 | * Copyright (C) 2014 Robert Jarzmik | ||
5 | * | ||
6 | * Heavily inspired from former arch/arm/mach-pxa/pxa25x.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 | * For non-devicetree platforms. Once pxa is fully converted to devicetree, this | ||
13 | * should go away. | ||
14 | */ | ||
15 | #include <linux/clk-provider.h> | ||
16 | #include <linux/clk.h> | ||
17 | #include <linux/clkdev.h> | ||
18 | #include <linux/io.h> | ||
19 | #include <linux/of.h> | ||
20 | #include <mach/pxa25x.h> | ||
21 | #include <mach/pxa2xx-regs.h> | ||
22 | |||
23 | #include <dt-bindings/clock/pxa-clock.h> | ||
24 | #include "clk-pxa.h" | ||
25 | |||
26 | #define KHz 1000 | ||
27 | #define MHz (1000 * 1000) | ||
28 | |||
29 | enum { | ||
30 | PXA_CORE_RUN = 0, | ||
31 | PXA_CORE_TURBO, | ||
32 | }; | ||
33 | |||
34 | /* | ||
35 | * Various clock factors driven by the CCCR register. | ||
36 | */ | ||
37 | |||
38 | /* Crystal Frequency to Memory Frequency Multiplier (L) */ | ||
39 | static unsigned char L_clk_mult[32] = { 0, 27, 32, 36, 40, 45, 0, }; | ||
40 | |||
41 | /* Memory Frequency to Run Mode Frequency Multiplier (M) */ | ||
42 | static unsigned char M_clk_mult[4] = { 0, 1, 2, 4 }; | ||
43 | |||
44 | /* Run Mode Frequency to Turbo Mode Frequency Multiplier (N) */ | ||
45 | /* Note: we store the value N * 2 here. */ | ||
46 | static unsigned char N2_clk_mult[8] = { 0, 0, 2, 3, 4, 0, 6, 0 }; | ||
47 | |||
48 | static const char * const get_freq_khz[] = { | ||
49 | "core", "run", "cpll", "memory" | ||
50 | }; | ||
51 | |||
52 | /* | ||
53 | * Get the clock frequency as reflected by CCCR and the turbo flag. | ||
54 | * We assume these values have been applied via a fcs. | ||
55 | * If info is not 0 we also display the current settings. | ||
56 | */ | ||
57 | unsigned int pxa25x_get_clk_frequency_khz(int info) | ||
58 | { | ||
59 | struct clk *clk; | ||
60 | unsigned long clks[5]; | ||
61 | int i; | ||
62 | |||
63 | for (i = 0; i < ARRAY_SIZE(get_freq_khz); i++) { | ||
64 | clk = clk_get(NULL, get_freq_khz[i]); | ||
65 | if (IS_ERR(clk)) { | ||
66 | clks[i] = 0; | ||
67 | } else { | ||
68 | clks[i] = clk_get_rate(clk); | ||
69 | clk_put(clk); | ||
70 | } | ||
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 | } | ||
81 | |||
82 | return (unsigned int)clks[0]; | ||
83 | } | ||
84 | |||
85 | static unsigned long clk_pxa25x_memory_get_rate(struct clk_hw *hw, | ||
86 | unsigned long parent_rate) | ||
87 | { | ||
88 | unsigned long cccr = CCCR; | ||
89 | unsigned int m = M_clk_mult[(cccr >> 5) & 0x03]; | ||
90 | |||
91 | return parent_rate / m; | ||
92 | } | ||
93 | PARENTS(clk_pxa25x_memory) = { "run" }; | ||
94 | RATE_RO_OPS(clk_pxa25x_memory, "memory"); | ||
95 | |||
96 | PARENTS(pxa25x_pbus95) = { "ppll_95_85mhz", "ppll_95_85mhz" }; | ||
97 | PARENTS(pxa25x_pbus147) = { "ppll_147_46mhz", "ppll_147_46mhz" }; | ||
98 | PARENTS(pxa25x_osc3) = { "osc_3_6864mhz", "osc_3_6864mhz" }; | ||
99 | |||
100 | #define PXA25X_CKEN(dev_id, con_id, parents, mult, div, \ | ||
101 | bit, is_lp, flags) \ | ||
102 | PXA_CKEN(dev_id, con_id, bit, parents, mult, div, mult, div, \ | ||
103 | is_lp, &CKEN, CKEN_ ## bit, flags) | ||
104 | #define PXA25X_PBUS95_CKEN(dev_id, con_id, bit, mult_hp, div_hp, delay) \ | ||
105 | PXA25X_CKEN(dev_id, con_id, pxa25x_pbus95_parents, mult_hp, \ | ||
106 | div_hp, bit, NULL, 0) | ||
107 | #define PXA25X_PBUS147_CKEN(dev_id, con_id, bit, mult_hp, div_hp, delay)\ | ||
108 | PXA25X_CKEN(dev_id, con_id, pxa25x_pbus147_parents, mult_hp, \ | ||
109 | div_hp, bit, NULL, 0) | ||
110 | #define PXA25X_OSC3_CKEN(dev_id, con_id, bit, mult_hp, div_hp, delay) \ | ||
111 | PXA25X_CKEN(dev_id, con_id, pxa25x_osc3_parents, mult_hp, \ | ||
112 | div_hp, bit, NULL, 0) | ||
113 | |||
114 | #define PXA25X_CKEN_1RATE(dev_id, con_id, bit, parents, delay) \ | ||
115 | PXA_CKEN_1RATE(dev_id, con_id, bit, parents, \ | ||
116 | &CKEN, CKEN_ ## bit, 0) | ||
117 | #define PXA25X_CKEN_1RATE_AO(dev_id, con_id, bit, parents, delay) \ | ||
118 | PXA_CKEN_1RATE(dev_id, con_id, bit, parents, \ | ||
119 | &CKEN, CKEN_ ## bit, CLK_IGNORE_UNUSED) | ||
120 | |||
121 | static struct desc_clk_cken pxa25x_clocks[] __initdata = { | ||
122 | PXA25X_PBUS95_CKEN("pxa2xx-mci.0", NULL, MMC, 1, 5, 0), | ||
123 | PXA25X_PBUS95_CKEN("pxa2xx-i2c.0", NULL, I2C, 1, 3, 0), | ||
124 | PXA25X_PBUS95_CKEN("pxa2xx-ir", "FICPCLK", FICP, 1, 2, 0), | ||
125 | PXA25X_PBUS95_CKEN("pxa25x-udc", NULL, USB, 1, 2, 5), | ||
126 | PXA25X_PBUS147_CKEN("pxa2xx-uart.0", NULL, FFUART, 1, 10, 1), | ||
127 | PXA25X_PBUS147_CKEN("pxa2xx-uart.1", NULL, BTUART, 1, 10, 1), | ||
128 | PXA25X_PBUS147_CKEN("pxa2xx-uart.2", NULL, STUART, 1, 10, 1), | ||
129 | PXA25X_PBUS147_CKEN("pxa2xx-uart.3", NULL, HWUART, 1, 10, 1), | ||
130 | PXA25X_PBUS147_CKEN("pxa2xx-i2s", NULL, I2S, 1, 10, 0), | ||
131 | PXA25X_PBUS147_CKEN(NULL, "AC97CLK", AC97, 1, 12, 0), | ||
132 | PXA25X_OSC3_CKEN("pxa25x-ssp.0", NULL, SSP, 1, 1, 0), | ||
133 | PXA25X_OSC3_CKEN("pxa25x-nssp.1", NULL, NSSP, 1, 1, 0), | ||
134 | PXA25X_OSC3_CKEN("pxa25x-nssp.2", NULL, ASSP, 1, 1, 0), | ||
135 | PXA25X_OSC3_CKEN("pxa25x-pwm.0", NULL, PWM0, 1, 1, 0), | ||
136 | PXA25X_OSC3_CKEN("pxa25x-pwm.1", NULL, PWM1, 1, 1, 0), | ||
137 | |||
138 | PXA25X_CKEN_1RATE("pxa2xx-fb", NULL, LCD, clk_pxa25x_memory_parents, 0), | ||
139 | PXA25X_CKEN_1RATE_AO("pxa2xx-pcmcia", NULL, MEMC, | ||
140 | clk_pxa25x_memory_parents, 0), | ||
141 | }; | ||
142 | |||
143 | static u8 clk_pxa25x_core_get_parent(struct clk_hw *hw) | ||
144 | { | ||
145 | unsigned long clkcfg; | ||
146 | unsigned int t; | ||
147 | |||
148 | asm("mrc\tp14, 0, %0, c6, c0, 0" : "=r" (clkcfg)); | ||
149 | t = clkcfg & (1 << 0); | ||
150 | if (t) | ||
151 | return PXA_CORE_TURBO; | ||
152 | return PXA_CORE_RUN; | ||
153 | } | ||
154 | |||
155 | static unsigned long clk_pxa25x_core_get_rate(struct clk_hw *hw, | ||
156 | unsigned long parent_rate) | ||
157 | { | ||
158 | return parent_rate; | ||
159 | } | ||
160 | PARENTS(clk_pxa25x_core) = { "run", "cpll" }; | ||
161 | MUX_RO_RATE_RO_OPS(clk_pxa25x_core, "core"); | ||
162 | |||
163 | static unsigned long clk_pxa25x_run_get_rate(struct clk_hw *hw, | ||
164 | unsigned long parent_rate) | ||
165 | { | ||
166 | unsigned long cccr = CCCR; | ||
167 | unsigned int n2 = N2_clk_mult[(cccr >> 7) & 0x07]; | ||
168 | |||
169 | return (parent_rate / n2) * 2; | ||
170 | } | ||
171 | PARENTS(clk_pxa25x_run) = { "cpll" }; | ||
172 | RATE_RO_OPS(clk_pxa25x_run, "run"); | ||
173 | |||
174 | static unsigned long clk_pxa25x_cpll_get_rate(struct clk_hw *hw, | ||
175 | unsigned long parent_rate) | ||
176 | { | ||
177 | unsigned long clkcfg, cccr = CCCR; | ||
178 | unsigned int l, m, n2, t; | ||
179 | |||
180 | asm("mrc\tp14, 0, %0, c6, c0, 0" : "=r" (clkcfg)); | ||
181 | t = clkcfg & (1 << 0); | ||
182 | l = L_clk_mult[(cccr >> 0) & 0x1f]; | ||
183 | m = M_clk_mult[(cccr >> 5) & 0x03]; | ||
184 | n2 = N2_clk_mult[(cccr >> 7) & 0x07]; | ||
185 | |||
186 | if (t) | ||
187 | return m * l * n2 * parent_rate / 2; | ||
188 | return m * l * parent_rate; | ||
189 | } | ||
190 | PARENTS(clk_pxa25x_cpll) = { "osc_3_6864mhz" }; | ||
191 | RATE_RO_OPS(clk_pxa25x_cpll, "cpll"); | ||
192 | |||
193 | static void __init pxa25x_register_core(void) | ||
194 | { | ||
195 | clk_register_clk_pxa25x_cpll(); | ||
196 | clk_register_clk_pxa25x_run(); | ||
197 | clkdev_pxa_register(CLK_CORE, "core", NULL, | ||
198 | clk_register_clk_pxa25x_core()); | ||
199 | } | ||
200 | |||
201 | static void __init pxa25x_register_plls(void) | ||
202 | { | ||
203 | clk_register_fixed_rate(NULL, "osc_3_6864mhz", NULL, | ||
204 | CLK_GET_RATE_NOCACHE | CLK_IS_ROOT, | ||
205 | 3686400); | ||
206 | clk_register_fixed_rate(NULL, "osc_32_768khz", NULL, | ||
207 | CLK_GET_RATE_NOCACHE | CLK_IS_ROOT, | ||
208 | 32768); | ||
209 | clk_register_fixed_rate(NULL, "clk_dummy", NULL, CLK_IS_ROOT, 0); | ||
210 | clk_register_fixed_factor(NULL, "ppll_95_85mhz", "osc_3_6864mhz", | ||
211 | 0, 26, 1); | ||
212 | clk_register_fixed_factor(NULL, "ppll_147_46mhz", "osc_3_6864mhz", | ||
213 | 0, 40, 1); | ||
214 | } | ||
215 | |||
216 | static void __init pxa25x_base_clocks_init(void) | ||
217 | { | ||
218 | pxa25x_register_plls(); | ||
219 | pxa25x_register_core(); | ||
220 | clk_register_clk_pxa25x_memory(); | ||
221 | } | ||
222 | |||
223 | #define DUMMY_CLK(_con_id, _dev_id, _parent) \ | ||
224 | { .con_id = _con_id, .dev_id = _dev_id, .parent = _parent } | ||
225 | struct dummy_clk { | ||
226 | const char *con_id; | ||
227 | const char *dev_id; | ||
228 | const char *parent; | ||
229 | }; | ||
230 | static struct dummy_clk dummy_clks[] __initdata = { | ||
231 | DUMMY_CLK(NULL, "pxa25x-gpio", "osc_32_768khz"), | ||
232 | DUMMY_CLK(NULL, "pxa26x-gpio", "osc_32_768khz"), | ||
233 | DUMMY_CLK("GPIO11_CLK", NULL, "osc_3_6864mhz"), | ||
234 | DUMMY_CLK("GPIO12_CLK", NULL, "osc_32_768khz"), | ||
235 | DUMMY_CLK(NULL, "sa1100-rtc", "osc_32_768khz"), | ||
236 | DUMMY_CLK("OSTIMER0", NULL, "osc_32_768khz"), | ||
237 | DUMMY_CLK("UARTCLK", "pxa2xx-ir", "STUART"), | ||
238 | }; | ||
239 | |||
240 | static void __init pxa25x_dummy_clocks_init(void) | ||
241 | { | ||
242 | struct clk *clk; | ||
243 | struct dummy_clk *d; | ||
244 | const char *name; | ||
245 | int i; | ||
246 | |||
247 | /* | ||
248 | * All pinctrl logic has been wiped out of the clock driver, especially | ||
249 | * for gpio11 and gpio12 outputs. Machine code should ensure proper pin | ||
250 | * control (ie. pxa2xx_mfp_config() invocation). | ||
251 | */ | ||
252 | for (i = 0; i < ARRAY_SIZE(dummy_clks); i++) { | ||
253 | d = &dummy_clks[i]; | ||
254 | name = d->dev_id ? d->dev_id : d->con_id; | ||
255 | clk = clk_register_fixed_factor(NULL, name, d->parent, 0, 1, 1); | ||
256 | clk_register_clkdev(clk, d->con_id, d->dev_id); | ||
257 | } | ||
258 | } | ||
259 | |||
260 | int __init pxa25x_clocks_init(void) | ||
261 | { | ||
262 | pxa25x_base_clocks_init(); | ||
263 | pxa25x_dummy_clocks_init(); | ||
264 | return clk_pxa_cken_init(pxa25x_clocks, ARRAY_SIZE(pxa25x_clocks)); | ||
265 | } | ||
266 | |||
267 | static void __init pxa25x_dt_clocks_init(struct device_node *np) | ||
268 | { | ||
269 | pxa25x_clocks_init(); | ||
270 | clk_pxa_dt_common_init(np); | ||
271 | } | ||
272 | CLK_OF_DECLARE(pxa25x_clks, "marvell,pxa250-core-clocks", | ||
273 | pxa25x_dt_clocks_init); | ||