1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Mediatek MT7621 Clock Driver |
4 | * Author: Sergio Paracuellos <sergio.paracuellos@gmail.com> |
5 | */ |
6 | |
7 | #include <linux/bitfield.h> |
8 | #include <linux/bitops.h> |
9 | #include <linux/clk-provider.h> |
10 | #include <linux/clk.h> |
11 | #include <linux/mfd/syscon.h> |
12 | #include <linux/platform_device.h> |
13 | #include <linux/regmap.h> |
14 | #include <linux/reset-controller.h> |
15 | #include <linux/slab.h> |
16 | #include <dt-bindings/clock/mt7621-clk.h> |
17 | #include <dt-bindings/reset/mt7621-reset.h> |
18 | |
19 | /* Configuration registers */ |
20 | #define SYSC_REG_SYSTEM_CONFIG0 0x10 |
21 | #define SYSC_REG_SYSTEM_CONFIG1 0x14 |
22 | #define SYSC_REG_CLKCFG0 0x2c |
23 | #define SYSC_REG_CLKCFG1 0x30 |
24 | #define SYSC_REG_RESET_CTRL 0x34 |
25 | #define SYSC_REG_CUR_CLK_STS 0x44 |
26 | #define MEMC_REG_CPU_PLL 0x648 |
27 | |
28 | #define XTAL_MODE_SEL_MASK GENMASK(8, 6) |
29 | #define CPU_CLK_SEL_MASK GENMASK(31, 30) |
30 | #define CUR_CPU_FDIV_MASK GENMASK(12, 8) |
31 | #define CUR_CPU_FFRAC_MASK GENMASK(4, 0) |
32 | #define CPU_PLL_PREDIV_MASK GENMASK(13, 12) |
33 | #define CPU_PLL_FBDIV_MASK GENMASK(10, 4) |
34 | |
35 | struct mt7621_clk_priv { |
36 | struct regmap *sysc; |
37 | struct regmap *memc; |
38 | }; |
39 | |
40 | struct mt7621_clk { |
41 | struct clk_hw hw; |
42 | struct mt7621_clk_priv *priv; |
43 | }; |
44 | |
45 | struct mt7621_fixed_clk { |
46 | u8 idx; |
47 | const char *name; |
48 | const char *parent_name; |
49 | unsigned long rate; |
50 | struct clk_hw *hw; |
51 | }; |
52 | |
53 | struct mt7621_gate { |
54 | u8 idx; |
55 | const char *name; |
56 | const char *parent_name; |
57 | struct mt7621_clk_priv *priv; |
58 | u32 bit_idx; |
59 | struct clk_hw hw; |
60 | }; |
61 | |
62 | #define GATE(_id, _name, _pname, _shift) \ |
63 | { \ |
64 | .idx = _id, \ |
65 | .name = _name, \ |
66 | .parent_name = _pname, \ |
67 | .bit_idx = _shift \ |
68 | } |
69 | |
70 | static struct mt7621_gate mt7621_gates[] = { |
71 | GATE(MT7621_CLK_HSDMA, "hsdma" , "150m" , BIT(5)), |
72 | GATE(MT7621_CLK_FE, "fe" , "250m" , BIT(6)), |
73 | GATE(MT7621_CLK_SP_DIVTX, "sp_divtx" , "270m" , BIT(7)), |
74 | GATE(MT7621_CLK_TIMER, "timer" , "50m" , BIT(8)), |
75 | GATE(MT7621_CLK_PCM, "pcm" , "270m" , BIT(11)), |
76 | GATE(MT7621_CLK_PIO, "pio" , "50m" , BIT(13)), |
77 | GATE(MT7621_CLK_GDMA, "gdma" , "bus" , BIT(14)), |
78 | GATE(MT7621_CLK_NAND, "nand" , "125m" , BIT(15)), |
79 | GATE(MT7621_CLK_I2C, "i2c" , "50m" , BIT(16)), |
80 | GATE(MT7621_CLK_I2S, "i2s" , "270m" , BIT(17)), |
81 | GATE(MT7621_CLK_SPI, "spi" , "bus" , BIT(18)), |
82 | GATE(MT7621_CLK_UART1, "uart1" , "50m" , BIT(19)), |
83 | GATE(MT7621_CLK_UART2, "uart2" , "50m" , BIT(20)), |
84 | GATE(MT7621_CLK_UART3, "uart3" , "50m" , BIT(21)), |
85 | GATE(MT7621_CLK_ETH, "eth" , "50m" , BIT(23)), |
86 | GATE(MT7621_CLK_PCIE0, "pcie0" , "125m" , BIT(24)), |
87 | GATE(MT7621_CLK_PCIE1, "pcie1" , "125m" , BIT(25)), |
88 | GATE(MT7621_CLK_PCIE2, "pcie2" , "125m" , BIT(26)), |
89 | GATE(MT7621_CLK_CRYPTO, "crypto" , "250m" , BIT(29)), |
90 | GATE(MT7621_CLK_SHXC, "shxc" , "50m" , BIT(30)) |
91 | }; |
92 | |
93 | static inline struct mt7621_gate *to_mt7621_gate(struct clk_hw *hw) |
94 | { |
95 | return container_of(hw, struct mt7621_gate, hw); |
96 | } |
97 | |
98 | static int mt7621_gate_enable(struct clk_hw *hw) |
99 | { |
100 | struct mt7621_gate *clk_gate = to_mt7621_gate(hw); |
101 | struct regmap *sysc = clk_gate->priv->sysc; |
102 | |
103 | return regmap_update_bits(map: sysc, SYSC_REG_CLKCFG1, |
104 | mask: clk_gate->bit_idx, val: clk_gate->bit_idx); |
105 | } |
106 | |
107 | static void mt7621_gate_disable(struct clk_hw *hw) |
108 | { |
109 | struct mt7621_gate *clk_gate = to_mt7621_gate(hw); |
110 | struct regmap *sysc = clk_gate->priv->sysc; |
111 | |
112 | regmap_update_bits(map: sysc, SYSC_REG_CLKCFG1, mask: clk_gate->bit_idx, val: 0); |
113 | } |
114 | |
115 | static int mt7621_gate_is_enabled(struct clk_hw *hw) |
116 | { |
117 | struct mt7621_gate *clk_gate = to_mt7621_gate(hw); |
118 | struct regmap *sysc = clk_gate->priv->sysc; |
119 | u32 val; |
120 | |
121 | if (regmap_read(map: sysc, SYSC_REG_CLKCFG1, val: &val)) |
122 | return 0; |
123 | |
124 | return val & clk_gate->bit_idx; |
125 | } |
126 | |
127 | static const struct clk_ops mt7621_gate_ops = { |
128 | .enable = mt7621_gate_enable, |
129 | .disable = mt7621_gate_disable, |
130 | .is_enabled = mt7621_gate_is_enabled, |
131 | }; |
132 | |
133 | static int mt7621_gate_ops_init(struct device *dev, |
134 | struct mt7621_gate *sclk) |
135 | { |
136 | /* |
137 | * There are drivers for this SoC that are older |
138 | * than clock driver and are not prepared for the clock. |
139 | * We don't want the kernel to disable anything so we |
140 | * add CLK_IS_CRITICAL flag here. |
141 | */ |
142 | struct clk_init_data init = { |
143 | .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, |
144 | .num_parents = 1, |
145 | .parent_names = &sclk->parent_name, |
146 | .ops = &mt7621_gate_ops, |
147 | .name = sclk->name, |
148 | }; |
149 | |
150 | sclk->hw.init = &init; |
151 | return devm_clk_hw_register(dev, hw: &sclk->hw); |
152 | } |
153 | |
154 | static int mt7621_register_gates(struct device *dev, |
155 | struct clk_hw_onecell_data *clk_data, |
156 | struct mt7621_clk_priv *priv) |
157 | { |
158 | struct clk_hw **hws = clk_data->hws; |
159 | struct mt7621_gate *sclk; |
160 | int ret, i; |
161 | |
162 | for (i = 0; i < ARRAY_SIZE(mt7621_gates); i++) { |
163 | sclk = &mt7621_gates[i]; |
164 | sclk->priv = priv; |
165 | ret = mt7621_gate_ops_init(dev, sclk); |
166 | if (ret) { |
167 | dev_err(dev, "Couldn't register clock %s\n" , sclk->name); |
168 | goto err_clk_unreg; |
169 | } |
170 | |
171 | hws[sclk->idx] = &sclk->hw; |
172 | } |
173 | |
174 | return 0; |
175 | |
176 | err_clk_unreg: |
177 | while (--i >= 0) { |
178 | sclk = &mt7621_gates[i]; |
179 | clk_hw_unregister(hw: &sclk->hw); |
180 | } |
181 | return ret; |
182 | } |
183 | |
184 | #define FIXED(_id, _name, _rate) \ |
185 | { \ |
186 | .idx = _id, \ |
187 | .name = _name, \ |
188 | .parent_name = "xtal", \ |
189 | .rate = _rate \ |
190 | } |
191 | |
192 | static struct mt7621_fixed_clk mt7621_fixed_clks[] = { |
193 | FIXED(MT7621_CLK_50M, "50m" , 50000000), |
194 | FIXED(MT7621_CLK_125M, "125m" , 125000000), |
195 | FIXED(MT7621_CLK_150M, "150m" , 150000000), |
196 | FIXED(MT7621_CLK_250M, "250m" , 250000000), |
197 | FIXED(MT7621_CLK_270M, "270m" , 270000000), |
198 | }; |
199 | |
200 | static int mt7621_register_fixed_clocks(struct device *dev, |
201 | struct clk_hw_onecell_data *clk_data) |
202 | { |
203 | struct clk_hw **hws = clk_data->hws; |
204 | struct mt7621_fixed_clk *sclk; |
205 | int ret, i; |
206 | |
207 | for (i = 0; i < ARRAY_SIZE(mt7621_fixed_clks); i++) { |
208 | sclk = &mt7621_fixed_clks[i]; |
209 | sclk->hw = clk_hw_register_fixed_rate(dev, sclk->name, |
210 | sclk->parent_name, 0, |
211 | sclk->rate); |
212 | if (IS_ERR(ptr: sclk->hw)) { |
213 | dev_err(dev, "Couldn't register clock %s\n" , sclk->name); |
214 | ret = PTR_ERR(ptr: sclk->hw); |
215 | goto err_clk_unreg; |
216 | } |
217 | |
218 | hws[sclk->idx] = sclk->hw; |
219 | } |
220 | |
221 | return 0; |
222 | |
223 | err_clk_unreg: |
224 | while (--i >= 0) { |
225 | sclk = &mt7621_fixed_clks[i]; |
226 | clk_hw_unregister_fixed_rate(hw: sclk->hw); |
227 | } |
228 | return ret; |
229 | } |
230 | |
231 | static inline struct mt7621_clk *to_mt7621_clk(struct clk_hw *hw) |
232 | { |
233 | return container_of(hw, struct mt7621_clk, hw); |
234 | } |
235 | |
236 | static unsigned long mt7621_xtal_recalc_rate(struct clk_hw *hw, |
237 | unsigned long parent_rate) |
238 | { |
239 | struct mt7621_clk *clk = to_mt7621_clk(hw); |
240 | struct regmap *sysc = clk->priv->sysc; |
241 | u32 val; |
242 | |
243 | regmap_read(map: sysc, SYSC_REG_SYSTEM_CONFIG0, val: &val); |
244 | val = FIELD_GET(XTAL_MODE_SEL_MASK, val); |
245 | |
246 | if (val <= 2) |
247 | return 20000000; |
248 | if (val <= 5) |
249 | return 40000000; |
250 | |
251 | return 25000000; |
252 | } |
253 | |
254 | static unsigned long mt7621_cpu_recalc_rate(struct clk_hw *hw, |
255 | unsigned long xtal_clk) |
256 | { |
257 | static const u32 prediv_tbl[] = { 0, 1, 2, 2 }; |
258 | struct mt7621_clk *clk = to_mt7621_clk(hw); |
259 | struct regmap *sysc = clk->priv->sysc; |
260 | struct regmap *memc = clk->priv->memc; |
261 | u32 clkcfg, clk_sel, curclk, ffiv, ffrac; |
262 | u32 pll, prediv, fbdiv; |
263 | unsigned long cpu_clk; |
264 | |
265 | regmap_read(map: sysc, SYSC_REG_CLKCFG0, val: &clkcfg); |
266 | clk_sel = FIELD_GET(CPU_CLK_SEL_MASK, clkcfg); |
267 | |
268 | regmap_read(map: sysc, SYSC_REG_CUR_CLK_STS, val: &curclk); |
269 | ffiv = FIELD_GET(CUR_CPU_FDIV_MASK, curclk); |
270 | ffrac = FIELD_GET(CUR_CPU_FFRAC_MASK, curclk); |
271 | |
272 | switch (clk_sel) { |
273 | case 0: |
274 | cpu_clk = 500000000; |
275 | break; |
276 | case 1: |
277 | regmap_read(map: memc, MEMC_REG_CPU_PLL, val: &pll); |
278 | fbdiv = FIELD_GET(CPU_PLL_FBDIV_MASK, pll); |
279 | prediv = FIELD_GET(CPU_PLL_PREDIV_MASK, pll); |
280 | cpu_clk = ((fbdiv + 1) * xtal_clk) >> prediv_tbl[prediv]; |
281 | break; |
282 | default: |
283 | cpu_clk = xtal_clk; |
284 | } |
285 | |
286 | return cpu_clk / ffiv * ffrac; |
287 | } |
288 | |
289 | static unsigned long mt7621_bus_recalc_rate(struct clk_hw *hw, |
290 | unsigned long parent_rate) |
291 | { |
292 | return parent_rate / 4; |
293 | } |
294 | |
295 | #define CLK_BASE(_name, _parent, _recalc) { \ |
296 | .init = &(struct clk_init_data) { \ |
297 | .name = _name, \ |
298 | .ops = &(const struct clk_ops) { \ |
299 | .recalc_rate = _recalc, \ |
300 | }, \ |
301 | .parent_data = &(const struct clk_parent_data) { \ |
302 | .name = _parent, \ |
303 | .fw_name = _parent \ |
304 | }, \ |
305 | .num_parents = _parent ? 1 : 0 \ |
306 | }, \ |
307 | } |
308 | |
309 | static struct mt7621_clk mt7621_clks_base[] = { |
310 | { CLK_BASE("xtal" , NULL, mt7621_xtal_recalc_rate) }, |
311 | { CLK_BASE("cpu" , "xtal" , mt7621_cpu_recalc_rate) }, |
312 | { CLK_BASE("bus" , "cpu" , mt7621_bus_recalc_rate) }, |
313 | }; |
314 | |
315 | static struct clk_hw *mt7621_clk_early[MT7621_CLK_MAX]; |
316 | |
317 | static int mt7621_register_early_clocks(struct device_node *np, |
318 | struct clk_hw_onecell_data *clk_data, |
319 | struct mt7621_clk_priv *priv) |
320 | { |
321 | struct clk_hw **hws = clk_data->hws; |
322 | struct mt7621_clk *sclk; |
323 | int ret, i, j; |
324 | |
325 | for (i = 0; i < ARRAY_SIZE(mt7621_clks_base); i++) { |
326 | sclk = &mt7621_clks_base[i]; |
327 | sclk->priv = priv; |
328 | ret = of_clk_hw_register(node: np, hw: &sclk->hw); |
329 | if (ret) { |
330 | pr_err("Couldn't register top clock %i\n" , i); |
331 | goto err_clk_unreg; |
332 | } |
333 | |
334 | hws[i] = &sclk->hw; |
335 | mt7621_clk_early[i] = &sclk->hw; |
336 | } |
337 | |
338 | for (j = i; j < MT7621_CLK_MAX; j++) |
339 | mt7621_clk_early[j] = ERR_PTR(error: -EPROBE_DEFER); |
340 | |
341 | return 0; |
342 | |
343 | err_clk_unreg: |
344 | while (--i >= 0) { |
345 | sclk = &mt7621_clks_base[i]; |
346 | clk_hw_unregister(hw: &sclk->hw); |
347 | } |
348 | return ret; |
349 | } |
350 | |
351 | static void __init mt7621_clk_init(struct device_node *node) |
352 | { |
353 | struct mt7621_clk_priv *priv; |
354 | struct clk_hw_onecell_data *clk_data; |
355 | int ret, i, count; |
356 | |
357 | priv = kzalloc(size: sizeof(*priv), GFP_KERNEL); |
358 | if (!priv) |
359 | return; |
360 | |
361 | priv->sysc = syscon_node_to_regmap(np: node); |
362 | if (IS_ERR(ptr: priv->sysc)) { |
363 | pr_err("Could not get sysc syscon regmap\n" ); |
364 | goto free_clk_priv; |
365 | } |
366 | |
367 | priv->memc = syscon_regmap_lookup_by_phandle(np: node, property: "ralink,memctl" ); |
368 | if (IS_ERR(ptr: priv->memc)) { |
369 | pr_err("Could not get memc syscon regmap\n" ); |
370 | goto free_clk_priv; |
371 | } |
372 | |
373 | count = ARRAY_SIZE(mt7621_clks_base) + |
374 | ARRAY_SIZE(mt7621_fixed_clks) + ARRAY_SIZE(mt7621_gates); |
375 | clk_data = kzalloc(struct_size(clk_data, hws, count), GFP_KERNEL); |
376 | if (!clk_data) |
377 | goto free_clk_priv; |
378 | |
379 | ret = mt7621_register_early_clocks(np: node, clk_data, priv); |
380 | if (ret) { |
381 | pr_err("Couldn't register top clocks\n" ); |
382 | goto free_clk_data; |
383 | } |
384 | |
385 | clk_data->num = count; |
386 | |
387 | ret = of_clk_add_hw_provider(np: node, get: of_clk_hw_onecell_get, data: clk_data); |
388 | if (ret) { |
389 | pr_err("Couldn't add clk hw provider\n" ); |
390 | goto unreg_clk_top; |
391 | } |
392 | |
393 | return; |
394 | |
395 | unreg_clk_top: |
396 | for (i = 0; i < ARRAY_SIZE(mt7621_clks_base); i++) { |
397 | struct mt7621_clk *sclk = &mt7621_clks_base[i]; |
398 | |
399 | clk_hw_unregister(hw: &sclk->hw); |
400 | } |
401 | |
402 | free_clk_data: |
403 | kfree(objp: clk_data); |
404 | |
405 | free_clk_priv: |
406 | kfree(objp: priv); |
407 | } |
408 | CLK_OF_DECLARE_DRIVER(mt7621_clk, "mediatek,mt7621-sysc" , mt7621_clk_init); |
409 | |
410 | struct mt7621_rst { |
411 | struct reset_controller_dev rcdev; |
412 | struct regmap *sysc; |
413 | }; |
414 | |
415 | static struct mt7621_rst *to_mt7621_rst(struct reset_controller_dev *dev) |
416 | { |
417 | return container_of(dev, struct mt7621_rst, rcdev); |
418 | } |
419 | |
420 | static int mt7621_assert_device(struct reset_controller_dev *rcdev, |
421 | unsigned long id) |
422 | { |
423 | struct mt7621_rst *data = to_mt7621_rst(dev: rcdev); |
424 | struct regmap *sysc = data->sysc; |
425 | |
426 | return regmap_update_bits(map: sysc, SYSC_REG_RESET_CTRL, BIT(id), BIT(id)); |
427 | } |
428 | |
429 | static int mt7621_deassert_device(struct reset_controller_dev *rcdev, |
430 | unsigned long id) |
431 | { |
432 | struct mt7621_rst *data = to_mt7621_rst(dev: rcdev); |
433 | struct regmap *sysc = data->sysc; |
434 | |
435 | return regmap_update_bits(map: sysc, SYSC_REG_RESET_CTRL, BIT(id), val: 0); |
436 | } |
437 | |
438 | static int mt7621_reset_device(struct reset_controller_dev *rcdev, |
439 | unsigned long id) |
440 | { |
441 | int ret; |
442 | |
443 | ret = mt7621_assert_device(rcdev, id); |
444 | if (ret < 0) |
445 | return ret; |
446 | |
447 | return mt7621_deassert_device(rcdev, id); |
448 | } |
449 | |
450 | static int mt7621_rst_xlate(struct reset_controller_dev *rcdev, |
451 | const struct of_phandle_args *reset_spec) |
452 | { |
453 | unsigned long id = reset_spec->args[0]; |
454 | |
455 | if (id == MT7621_RST_SYS || id >= rcdev->nr_resets) |
456 | return -EINVAL; |
457 | |
458 | return id; |
459 | } |
460 | |
461 | static const struct reset_control_ops reset_ops = { |
462 | .reset = mt7621_reset_device, |
463 | .assert = mt7621_assert_device, |
464 | .deassert = mt7621_deassert_device |
465 | }; |
466 | |
467 | static int mt7621_reset_init(struct device *dev, struct regmap *sysc) |
468 | { |
469 | struct mt7621_rst *rst_data; |
470 | |
471 | rst_data = devm_kzalloc(dev, size: sizeof(*rst_data), GFP_KERNEL); |
472 | if (!rst_data) |
473 | return -ENOMEM; |
474 | |
475 | rst_data->sysc = sysc; |
476 | rst_data->rcdev.ops = &reset_ops; |
477 | rst_data->rcdev.owner = THIS_MODULE; |
478 | rst_data->rcdev.nr_resets = 32; |
479 | rst_data->rcdev.of_reset_n_cells = 1; |
480 | rst_data->rcdev.of_xlate = mt7621_rst_xlate; |
481 | rst_data->rcdev.of_node = dev_of_node(dev); |
482 | |
483 | return devm_reset_controller_register(dev, rcdev: &rst_data->rcdev); |
484 | } |
485 | |
486 | static int mt7621_clk_probe(struct platform_device *pdev) |
487 | { |
488 | struct device_node *np = pdev->dev.of_node; |
489 | struct clk_hw_onecell_data *clk_data; |
490 | struct device *dev = &pdev->dev; |
491 | struct mt7621_clk_priv *priv; |
492 | int ret, i, count; |
493 | |
494 | priv = devm_kzalloc(dev, size: sizeof(*priv), GFP_KERNEL); |
495 | if (!priv) |
496 | return -ENOMEM; |
497 | |
498 | priv->sysc = syscon_node_to_regmap(np); |
499 | if (IS_ERR(ptr: priv->sysc)) { |
500 | ret = PTR_ERR(ptr: priv->sysc); |
501 | dev_err(dev, "Could not get sysc syscon regmap\n" ); |
502 | return ret; |
503 | } |
504 | |
505 | priv->memc = syscon_regmap_lookup_by_phandle(np, property: "ralink,memctl" ); |
506 | if (IS_ERR(ptr: priv->memc)) { |
507 | ret = PTR_ERR(ptr: priv->memc); |
508 | dev_err(dev, "Could not get memc syscon regmap\n" ); |
509 | return ret; |
510 | } |
511 | |
512 | ret = mt7621_reset_init(dev, sysc: priv->sysc); |
513 | if (ret) { |
514 | dev_err(dev, "Could not init reset controller\n" ); |
515 | return ret; |
516 | } |
517 | |
518 | count = ARRAY_SIZE(mt7621_clks_base) + |
519 | ARRAY_SIZE(mt7621_fixed_clks) + ARRAY_SIZE(mt7621_gates); |
520 | clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, count), |
521 | GFP_KERNEL); |
522 | if (!clk_data) |
523 | return -ENOMEM; |
524 | clk_data->num = count; |
525 | |
526 | for (i = 0; i < ARRAY_SIZE(mt7621_clks_base); i++) |
527 | clk_data->hws[i] = mt7621_clk_early[i]; |
528 | |
529 | ret = mt7621_register_fixed_clocks(dev, clk_data); |
530 | if (ret) { |
531 | dev_err(dev, "Couldn't register fixed clocks\n" ); |
532 | return ret; |
533 | } |
534 | |
535 | ret = mt7621_register_gates(dev, clk_data, priv); |
536 | if (ret) { |
537 | dev_err(dev, "Couldn't register fixed clock gates\n" ); |
538 | goto unreg_clk_fixed; |
539 | } |
540 | |
541 | ret = devm_of_clk_add_hw_provider(dev, get: of_clk_hw_onecell_get, data: clk_data); |
542 | if (ret) { |
543 | dev_err(dev, "Couldn't add clk hw provider\n" ); |
544 | goto unreg_clk_gates; |
545 | } |
546 | |
547 | return 0; |
548 | |
549 | unreg_clk_gates: |
550 | for (i = 0; i < ARRAY_SIZE(mt7621_gates); i++) { |
551 | struct mt7621_gate *sclk = &mt7621_gates[i]; |
552 | |
553 | clk_hw_unregister(hw: &sclk->hw); |
554 | } |
555 | |
556 | unreg_clk_fixed: |
557 | for (i = 0; i < ARRAY_SIZE(mt7621_fixed_clks); i++) { |
558 | struct mt7621_fixed_clk *sclk = &mt7621_fixed_clks[i]; |
559 | |
560 | clk_hw_unregister_fixed_rate(hw: sclk->hw); |
561 | } |
562 | |
563 | return ret; |
564 | } |
565 | |
566 | static const struct of_device_id mt7621_clk_of_match[] = { |
567 | { .compatible = "mediatek,mt7621-sysc" }, |
568 | {} |
569 | }; |
570 | |
571 | static struct platform_driver mt7621_clk_driver = { |
572 | .probe = mt7621_clk_probe, |
573 | .driver = { |
574 | .name = "mt7621-clk" , |
575 | .of_match_table = mt7621_clk_of_match, |
576 | }, |
577 | }; |
578 | |
579 | static int __init mt7621_clk_reset_init(void) |
580 | { |
581 | return platform_driver_register(&mt7621_clk_driver); |
582 | } |
583 | arch_initcall(mt7621_clk_reset_init); |
584 | |