1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * MOXA ART SoCs clock driver. |
4 | * |
5 | * Copyright (C) 2013 Jonas Jensen |
6 | * |
7 | * Jonas Jensen <jonas.jensen@gmail.com> |
8 | */ |
9 | |
10 | #include <linux/clk.h> |
11 | #include <linux/clk-provider.h> |
12 | #include <linux/io.h> |
13 | #include <linux/of_address.h> |
14 | #include <linux/clkdev.h> |
15 | |
16 | static void __init moxart_of_pll_clk_init(struct device_node *node) |
17 | { |
18 | void __iomem *base; |
19 | struct clk_hw *hw; |
20 | struct clk *ref_clk; |
21 | unsigned int mul; |
22 | const char *name = node->name; |
23 | const char *parent_name; |
24 | |
25 | of_property_read_string(np: node, propname: "clock-output-names" , out_string: &name); |
26 | parent_name = of_clk_get_parent_name(np: node, index: 0); |
27 | |
28 | base = of_iomap(node, index: 0); |
29 | if (!base) { |
30 | pr_err("%pOF: of_iomap failed\n" , node); |
31 | return; |
32 | } |
33 | |
34 | mul = readl(addr: base + 0x30) >> 3 & 0x3f; |
35 | iounmap(addr: base); |
36 | |
37 | ref_clk = of_clk_get(np: node, index: 0); |
38 | if (IS_ERR(ptr: ref_clk)) { |
39 | pr_err("%pOF: of_clk_get failed\n" , node); |
40 | return; |
41 | } |
42 | |
43 | hw = clk_hw_register_fixed_factor(NULL, name, parent_name, flags: 0, mult: mul, div: 1); |
44 | if (IS_ERR(ptr: hw)) { |
45 | pr_err("%pOF: failed to register clock\n" , node); |
46 | return; |
47 | } |
48 | |
49 | clk_hw_register_clkdev(hw, NULL, name); |
50 | of_clk_add_hw_provider(np: node, get: of_clk_hw_simple_get, data: hw); |
51 | } |
52 | CLK_OF_DECLARE(moxart_pll_clock, "moxa,moxart-pll-clock" , |
53 | moxart_of_pll_clk_init); |
54 | |
55 | static void __init moxart_of_apb_clk_init(struct device_node *node) |
56 | { |
57 | void __iomem *base; |
58 | struct clk_hw *hw; |
59 | struct clk *pll_clk; |
60 | unsigned int div, val; |
61 | unsigned int div_idx[] = { 2, 3, 4, 6, 8}; |
62 | const char *name = node->name; |
63 | const char *parent_name; |
64 | |
65 | of_property_read_string(np: node, propname: "clock-output-names" , out_string: &name); |
66 | parent_name = of_clk_get_parent_name(np: node, index: 0); |
67 | |
68 | base = of_iomap(node, index: 0); |
69 | if (!base) { |
70 | pr_err("%pOF: of_iomap failed\n" , node); |
71 | return; |
72 | } |
73 | |
74 | val = readl(addr: base + 0xc) >> 4 & 0x7; |
75 | iounmap(addr: base); |
76 | |
77 | if (val > 4) |
78 | val = 0; |
79 | div = div_idx[val] * 2; |
80 | |
81 | pll_clk = of_clk_get(np: node, index: 0); |
82 | if (IS_ERR(ptr: pll_clk)) { |
83 | pr_err("%pOF: of_clk_get failed\n" , node); |
84 | return; |
85 | } |
86 | |
87 | hw = clk_hw_register_fixed_factor(NULL, name, parent_name, flags: 0, mult: 1, div); |
88 | if (IS_ERR(ptr: hw)) { |
89 | pr_err("%pOF: failed to register clock\n" , node); |
90 | return; |
91 | } |
92 | |
93 | clk_hw_register_clkdev(hw, NULL, name); |
94 | of_clk_add_hw_provider(np: node, get: of_clk_hw_simple_get, data: hw); |
95 | } |
96 | CLK_OF_DECLARE(moxart_apb_clock, "moxa,moxart-apb-clock" , |
97 | moxart_of_apb_clk_init); |
98 | |