1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright 2013 Emilio López |
4 | * |
5 | * Emilio López <emilio@elopez.com.ar> |
6 | */ |
7 | |
8 | #include <linux/clk.h> |
9 | #include <linux/clk-provider.h> |
10 | #include <linux/io.h> |
11 | #include <linux/of_address.h> |
12 | #include <linux/platform_device.h> |
13 | #include <linux/slab.h> |
14 | |
15 | #include "clk-factors.h" |
16 | |
17 | /* |
18 | * sun4i_a10_get_mod0_factors() - calculates m, n factors for MOD0-style clocks |
19 | * MOD0 rate is calculated as follows |
20 | * rate = (parent_rate >> p) / (m + 1); |
21 | */ |
22 | |
23 | static void sun4i_a10_get_mod0_factors(struct factors_request *req) |
24 | { |
25 | u8 div, calcm, calcp; |
26 | |
27 | /* These clocks can only divide, so we will never be able to achieve |
28 | * frequencies higher than the parent frequency */ |
29 | if (req->rate > req->parent_rate) |
30 | req->rate = req->parent_rate; |
31 | |
32 | div = DIV_ROUND_UP(req->parent_rate, req->rate); |
33 | |
34 | if (div < 16) |
35 | calcp = 0; |
36 | else if (div / 2 < 16) |
37 | calcp = 1; |
38 | else if (div / 4 < 16) |
39 | calcp = 2; |
40 | else |
41 | calcp = 3; |
42 | |
43 | calcm = DIV_ROUND_UP(div, 1 << calcp); |
44 | |
45 | req->rate = (req->parent_rate >> calcp) / calcm; |
46 | req->m = calcm - 1; |
47 | req->p = calcp; |
48 | } |
49 | |
50 | /* user manual says "n" but it's really "p" */ |
51 | static const struct clk_factors_config sun4i_a10_mod0_config = { |
52 | .mshift = 0, |
53 | .mwidth = 4, |
54 | .pshift = 16, |
55 | .pwidth = 2, |
56 | }; |
57 | |
58 | static const struct factors_data sun4i_a10_mod0_data = { |
59 | .enable = 31, |
60 | .mux = 24, |
61 | .muxmask = BIT(1) | BIT(0), |
62 | .table = &sun4i_a10_mod0_config, |
63 | .getter = sun4i_a10_get_mod0_factors, |
64 | }; |
65 | |
66 | static DEFINE_SPINLOCK(sun4i_a10_mod0_lock); |
67 | |
68 | static void __init sun4i_a10_mod0_setup(struct device_node *node) |
69 | { |
70 | void __iomem *reg; |
71 | |
72 | reg = of_iomap(node, index: 0); |
73 | if (!reg) { |
74 | /* |
75 | * This happens with mod0 clk nodes instantiated through |
76 | * mfd, as those do not have their resources assigned at |
77 | * CLK_OF_DECLARE time yet, so do not print an error. |
78 | */ |
79 | return; |
80 | } |
81 | |
82 | sunxi_factors_register(node, data: &sun4i_a10_mod0_data, |
83 | lock: &sun4i_a10_mod0_lock, reg); |
84 | } |
85 | CLK_OF_DECLARE_DRIVER(sun4i_a10_mod0, "allwinner,sun4i-a10-mod0-clk" , |
86 | sun4i_a10_mod0_setup); |
87 | |
88 | static int sun4i_a10_mod0_clk_probe(struct platform_device *pdev) |
89 | { |
90 | struct device_node *np = pdev->dev.of_node; |
91 | void __iomem *reg; |
92 | |
93 | if (!np) |
94 | return -ENODEV; |
95 | |
96 | reg = devm_platform_ioremap_resource(pdev, index: 0); |
97 | if (IS_ERR(ptr: reg)) |
98 | return PTR_ERR(ptr: reg); |
99 | |
100 | sunxi_factors_register(node: np, data: &sun4i_a10_mod0_data, |
101 | lock: &sun4i_a10_mod0_lock, reg); |
102 | return 0; |
103 | } |
104 | |
105 | static const struct of_device_id sun4i_a10_mod0_clk_dt_ids[] = { |
106 | { .compatible = "allwinner,sun4i-a10-mod0-clk" }, |
107 | { /* sentinel */ } |
108 | }; |
109 | |
110 | static struct platform_driver sun4i_a10_mod0_clk_driver = { |
111 | .driver = { |
112 | .name = "sun4i-a10-mod0-clk" , |
113 | .of_match_table = sun4i_a10_mod0_clk_dt_ids, |
114 | }, |
115 | .probe = sun4i_a10_mod0_clk_probe, |
116 | }; |
117 | builtin_platform_driver(sun4i_a10_mod0_clk_driver); |
118 | |
119 | static const struct factors_data sun9i_a80_mod0_data __initconst = { |
120 | .enable = 31, |
121 | .mux = 24, |
122 | .muxmask = BIT(3) | BIT(2) | BIT(1) | BIT(0), |
123 | .table = &sun4i_a10_mod0_config, |
124 | .getter = sun4i_a10_get_mod0_factors, |
125 | }; |
126 | |
127 | static void __init sun9i_a80_mod0_setup(struct device_node *node) |
128 | { |
129 | void __iomem *reg; |
130 | |
131 | reg = of_io_request_and_map(device: node, index: 0, name: of_node_full_name(np: node)); |
132 | if (IS_ERR(ptr: reg)) { |
133 | pr_err("Could not get registers for mod0-clk: %pOFn\n" , |
134 | node); |
135 | return; |
136 | } |
137 | |
138 | sunxi_factors_register(node, data: &sun9i_a80_mod0_data, |
139 | lock: &sun4i_a10_mod0_lock, reg); |
140 | } |
141 | CLK_OF_DECLARE(sun9i_a80_mod0, "allwinner,sun9i-a80-mod0-clk" , sun9i_a80_mod0_setup); |
142 | |
143 | static DEFINE_SPINLOCK(sun5i_a13_mbus_lock); |
144 | |
145 | static void __init sun5i_a13_mbus_setup(struct device_node *node) |
146 | { |
147 | void __iomem *reg; |
148 | |
149 | reg = of_iomap(node, index: 0); |
150 | if (!reg) { |
151 | pr_err("Could not get registers for a13-mbus-clk\n" ); |
152 | return; |
153 | } |
154 | |
155 | /* The MBUS clocks needs to be always enabled */ |
156 | sunxi_factors_register_critical(node, data: &sun4i_a10_mod0_data, |
157 | lock: &sun5i_a13_mbus_lock, reg); |
158 | } |
159 | CLK_OF_DECLARE(sun5i_a13_mbus, "allwinner,sun5i-a13-mbus-clk" , sun5i_a13_mbus_setup); |
160 | |
161 | struct mmc_phase { |
162 | struct clk_hw hw; |
163 | u8 offset; |
164 | void __iomem *reg; |
165 | spinlock_t *lock; |
166 | }; |
167 | |
168 | #define to_mmc_phase(_hw) container_of(_hw, struct mmc_phase, hw) |
169 | |
170 | static int mmc_get_phase(struct clk_hw *hw) |
171 | { |
172 | struct clk *mmc, *mmc_parent, *clk = hw->clk; |
173 | struct mmc_phase *phase = to_mmc_phase(hw); |
174 | unsigned int mmc_rate, mmc_parent_rate; |
175 | u16 step, mmc_div; |
176 | u32 value; |
177 | u8 delay; |
178 | |
179 | value = readl(addr: phase->reg); |
180 | delay = (value >> phase->offset) & 0x3; |
181 | |
182 | if (!delay) |
183 | return 180; |
184 | |
185 | /* Get the main MMC clock */ |
186 | mmc = clk_get_parent(clk); |
187 | if (!mmc) |
188 | return -EINVAL; |
189 | |
190 | /* And its rate */ |
191 | mmc_rate = clk_get_rate(clk: mmc); |
192 | if (!mmc_rate) |
193 | return -EINVAL; |
194 | |
195 | /* Now, get the MMC parent (most likely some PLL) */ |
196 | mmc_parent = clk_get_parent(clk: mmc); |
197 | if (!mmc_parent) |
198 | return -EINVAL; |
199 | |
200 | /* And its rate */ |
201 | mmc_parent_rate = clk_get_rate(clk: mmc_parent); |
202 | if (!mmc_parent_rate) |
203 | return -EINVAL; |
204 | |
205 | /* Get MMC clock divider */ |
206 | mmc_div = mmc_parent_rate / mmc_rate; |
207 | |
208 | step = DIV_ROUND_CLOSEST(360, mmc_div); |
209 | return delay * step; |
210 | } |
211 | |
212 | static int mmc_set_phase(struct clk_hw *hw, int degrees) |
213 | { |
214 | struct clk *mmc, *mmc_parent, *clk = hw->clk; |
215 | struct mmc_phase *phase = to_mmc_phase(hw); |
216 | unsigned int mmc_rate, mmc_parent_rate; |
217 | unsigned long flags; |
218 | u32 value; |
219 | u8 delay; |
220 | |
221 | /* Get the main MMC clock */ |
222 | mmc = clk_get_parent(clk); |
223 | if (!mmc) |
224 | return -EINVAL; |
225 | |
226 | /* And its rate */ |
227 | mmc_rate = clk_get_rate(clk: mmc); |
228 | if (!mmc_rate) |
229 | return -EINVAL; |
230 | |
231 | /* Now, get the MMC parent (most likely some PLL) */ |
232 | mmc_parent = clk_get_parent(clk: mmc); |
233 | if (!mmc_parent) |
234 | return -EINVAL; |
235 | |
236 | /* And its rate */ |
237 | mmc_parent_rate = clk_get_rate(clk: mmc_parent); |
238 | if (!mmc_parent_rate) |
239 | return -EINVAL; |
240 | |
241 | if (degrees != 180) { |
242 | u16 step, mmc_div; |
243 | |
244 | /* Get MMC clock divider */ |
245 | mmc_div = mmc_parent_rate / mmc_rate; |
246 | |
247 | /* |
248 | * We can only outphase the clocks by multiple of the |
249 | * PLL's period. |
250 | * |
251 | * Since the MMC clock in only a divider, and the |
252 | * formula to get the outphasing in degrees is deg = |
253 | * 360 * delta / period |
254 | * |
255 | * If we simplify this formula, we can see that the |
256 | * only thing that we're concerned about is the number |
257 | * of period we want to outphase our clock from, and |
258 | * the divider set by the MMC clock. |
259 | */ |
260 | step = DIV_ROUND_CLOSEST(360, mmc_div); |
261 | delay = DIV_ROUND_CLOSEST(degrees, step); |
262 | } else { |
263 | delay = 0; |
264 | } |
265 | |
266 | spin_lock_irqsave(phase->lock, flags); |
267 | value = readl(addr: phase->reg); |
268 | value &= ~GENMASK(phase->offset + 3, phase->offset); |
269 | value |= delay << phase->offset; |
270 | writel(val: value, addr: phase->reg); |
271 | spin_unlock_irqrestore(lock: phase->lock, flags); |
272 | |
273 | return 0; |
274 | } |
275 | |
276 | static const struct clk_ops mmc_clk_ops = { |
277 | .get_phase = mmc_get_phase, |
278 | .set_phase = mmc_set_phase, |
279 | }; |
280 | |
281 | /* |
282 | * sunxi_mmc_setup - Common setup function for mmc module clocks |
283 | * |
284 | * The only difference between module clocks on different platforms is the |
285 | * width of the mux register bits and the valid values, which are passed in |
286 | * through struct factors_data. The phase clocks parts are identical. |
287 | */ |
288 | static void __init sunxi_mmc_setup(struct device_node *node, |
289 | const struct factors_data *data, |
290 | spinlock_t *lock) |
291 | { |
292 | struct clk_onecell_data *clk_data; |
293 | const char *parent; |
294 | void __iomem *reg; |
295 | int i; |
296 | |
297 | reg = of_io_request_and_map(device: node, index: 0, name: of_node_full_name(np: node)); |
298 | if (IS_ERR(ptr: reg)) { |
299 | pr_err("Couldn't map the %pOFn clock registers\n" , node); |
300 | return; |
301 | } |
302 | |
303 | clk_data = kmalloc(size: sizeof(*clk_data), GFP_KERNEL); |
304 | if (!clk_data) |
305 | return; |
306 | |
307 | clk_data->clks = kcalloc(n: 3, size: sizeof(*clk_data->clks), GFP_KERNEL); |
308 | if (!clk_data->clks) |
309 | goto err_free_data; |
310 | |
311 | clk_data->clk_num = 3; |
312 | clk_data->clks[0] = sunxi_factors_register(node, data, lock, reg); |
313 | if (!clk_data->clks[0]) |
314 | goto err_free_clks; |
315 | |
316 | parent = __clk_get_name(clk: clk_data->clks[0]); |
317 | |
318 | for (i = 1; i < 3; i++) { |
319 | struct clk_init_data init = { |
320 | .num_parents = 1, |
321 | .parent_names = &parent, |
322 | .ops = &mmc_clk_ops, |
323 | }; |
324 | struct mmc_phase *phase; |
325 | |
326 | phase = kmalloc(size: sizeof(*phase), GFP_KERNEL); |
327 | if (!phase) |
328 | continue; |
329 | |
330 | phase->hw.init = &init; |
331 | phase->reg = reg; |
332 | phase->lock = lock; |
333 | |
334 | if (i == 1) |
335 | phase->offset = 8; |
336 | else |
337 | phase->offset = 20; |
338 | |
339 | if (of_property_read_string_index(np: node, propname: "clock-output-names" , |
340 | index: i, output: &init.name)) |
341 | init.name = node->name; |
342 | |
343 | clk_data->clks[i] = clk_register(NULL, hw: &phase->hw); |
344 | if (IS_ERR(ptr: clk_data->clks[i])) { |
345 | kfree(objp: phase); |
346 | continue; |
347 | } |
348 | } |
349 | |
350 | of_clk_add_provider(np: node, clk_src_get: of_clk_src_onecell_get, data: clk_data); |
351 | |
352 | return; |
353 | |
354 | err_free_clks: |
355 | kfree(objp: clk_data->clks); |
356 | err_free_data: |
357 | kfree(objp: clk_data); |
358 | } |
359 | |
360 | static DEFINE_SPINLOCK(sun4i_a10_mmc_lock); |
361 | |
362 | static void __init sun4i_a10_mmc_setup(struct device_node *node) |
363 | { |
364 | sunxi_mmc_setup(node, data: &sun4i_a10_mod0_data, lock: &sun4i_a10_mmc_lock); |
365 | } |
366 | CLK_OF_DECLARE(sun4i_a10_mmc, "allwinner,sun4i-a10-mmc-clk" , sun4i_a10_mmc_setup); |
367 | |
368 | static DEFINE_SPINLOCK(sun9i_a80_mmc_lock); |
369 | |
370 | static void __init sun9i_a80_mmc_setup(struct device_node *node) |
371 | { |
372 | sunxi_mmc_setup(node, data: &sun9i_a80_mod0_data, lock: &sun9i_a80_mmc_lock); |
373 | } |
374 | CLK_OF_DECLARE(sun9i_a80_mmc, "allwinner,sun9i-a80-mmc-clk" , sun9i_a80_mmc_setup); |
375 | |