|
4 | 4 | * Author: Jerome Brunet <[email protected]> |
5 | 5 | */ |
6 | 6 |
|
| 7 | +#include <linux/device.h> |
7 | 8 | #include <linux/module.h> |
| 9 | +#include <linux/mfd/syscon.h> |
8 | 10 | #include "clk-regmap.h" |
9 | 11 |
|
| 12 | +int clk_regmap_init(struct clk_hw *hw) |
| 13 | +{ |
| 14 | + struct clk_regmap *clk = to_clk_regmap(hw); |
| 15 | + struct device_node *np, *parent_np; |
| 16 | + struct device *dev; |
| 17 | + |
| 18 | + /* Allow regmap to be preset as it was historically done */ |
| 19 | + if (clk->map) |
| 20 | + return 0; |
| 21 | + |
| 22 | + /* |
| 23 | + * FIXME: what follows couples the controller implementation |
| 24 | + * and clk_regmap clock type. This situation is not desirable |
| 25 | + * but temporary, until the controller is able to register |
| 26 | + * a hook to initialize a clock type |
| 27 | + */ |
| 28 | + |
| 29 | + /* Check the usual dev enabled controller with an basic IO regmap */ |
| 30 | + dev = clk_hw_get_dev(hw); |
| 31 | + if (dev) { |
| 32 | + clk->map = dev_get_regmap(dev, NULL); |
| 33 | + if (clk->map) |
| 34 | + return 0; |
| 35 | + } |
| 36 | + |
| 37 | + /* Move on to early and syscon based controllers */ |
| 38 | + np = clk_hw_get_of_node(hw); |
| 39 | + if (np) { |
| 40 | + parent_np = of_get_parent(np); |
| 41 | + clk->map = syscon_node_to_regmap(parent_np); |
| 42 | + of_node_put(parent_np); |
| 43 | + |
| 44 | + if (!IS_ERR_OR_NULL(clk->map)) |
| 45 | + return 0; |
| 46 | + } |
| 47 | + |
| 48 | + /* Bail out if regmap can't be found */ |
| 49 | + return -EINVAL; |
| 50 | +} |
| 51 | +EXPORT_SYMBOL_NS_GPL(clk_regmap_init, "CLK_MESON"); |
| 52 | + |
10 | 53 | static int clk_regmap_gate_endisable(struct clk_hw *hw, int enable) |
11 | 54 | { |
12 | 55 | struct clk_regmap *clk = to_clk_regmap(hw); |
@@ -45,13 +88,15 @@ static int clk_regmap_gate_is_enabled(struct clk_hw *hw) |
45 | 88 | } |
46 | 89 |
|
47 | 90 | const struct clk_ops clk_regmap_gate_ops = { |
| 91 | + .init = clk_regmap_init, |
48 | 92 | .enable = clk_regmap_gate_enable, |
49 | 93 | .disable = clk_regmap_gate_disable, |
50 | 94 | .is_enabled = clk_regmap_gate_is_enabled, |
51 | 95 | }; |
52 | 96 | EXPORT_SYMBOL_NS_GPL(clk_regmap_gate_ops, "CLK_MESON"); |
53 | 97 |
|
54 | 98 | const struct clk_ops clk_regmap_gate_ro_ops = { |
| 99 | + .init = clk_regmap_init, |
55 | 100 | .is_enabled = clk_regmap_gate_is_enabled, |
56 | 101 | }; |
57 | 102 | EXPORT_SYMBOL_NS_GPL(clk_regmap_gate_ro_ops, "CLK_MESON"); |
@@ -121,13 +166,15 @@ static int clk_regmap_div_set_rate(struct clk_hw *hw, unsigned long rate, |
121 | 166 | /* Would prefer clk_regmap_div_ro_ops but clashes with qcom */ |
122 | 167 |
|
123 | 168 | const struct clk_ops clk_regmap_divider_ops = { |
| 169 | + .init = clk_regmap_init, |
124 | 170 | .recalc_rate = clk_regmap_div_recalc_rate, |
125 | 171 | .determine_rate = clk_regmap_div_determine_rate, |
126 | 172 | .set_rate = clk_regmap_div_set_rate, |
127 | 173 | }; |
128 | 174 | EXPORT_SYMBOL_NS_GPL(clk_regmap_divider_ops, "CLK_MESON"); |
129 | 175 |
|
130 | 176 | const struct clk_ops clk_regmap_divider_ro_ops = { |
| 177 | + .init = clk_regmap_init, |
131 | 178 | .recalc_rate = clk_regmap_div_recalc_rate, |
132 | 179 | .determine_rate = clk_regmap_div_determine_rate, |
133 | 180 | }; |
@@ -170,13 +217,15 @@ static int clk_regmap_mux_determine_rate(struct clk_hw *hw, |
170 | 217 | } |
171 | 218 |
|
172 | 219 | const struct clk_ops clk_regmap_mux_ops = { |
| 220 | + .init = clk_regmap_init, |
173 | 221 | .get_parent = clk_regmap_mux_get_parent, |
174 | 222 | .set_parent = clk_regmap_mux_set_parent, |
175 | 223 | .determine_rate = clk_regmap_mux_determine_rate, |
176 | 224 | }; |
177 | 225 | EXPORT_SYMBOL_NS_GPL(clk_regmap_mux_ops, "CLK_MESON"); |
178 | 226 |
|
179 | 227 | const struct clk_ops clk_regmap_mux_ro_ops = { |
| 228 | + .init = clk_regmap_init, |
180 | 229 | .get_parent = clk_regmap_mux_get_parent, |
181 | 230 | }; |
182 | 231 | EXPORT_SYMBOL_NS_GPL(clk_regmap_mux_ro_ops, "CLK_MESON"); |
|
0 commit comments