diff options
Diffstat (limited to 'drivers/clk/meson/clk-regmap.c')
| -rw-r--r-- | drivers/clk/meson/clk-regmap.c | 63 |
1 files changed, 56 insertions, 7 deletions
diff --git a/drivers/clk/meson/clk-regmap.c b/drivers/clk/meson/clk-regmap.c index 07f7e441b916..1ed56fe63cae 100644 --- a/drivers/clk/meson/clk-regmap.c +++ b/drivers/clk/meson/clk-regmap.c @@ -4,9 +4,52 @@ * Author: Jerome Brunet <jbrunet@baylibre.com> */ +#include <linux/device.h> #include <linux/module.h> +#include <linux/mfd/syscon.h> #include "clk-regmap.h" +int clk_regmap_init(struct clk_hw *hw) +{ + struct clk_regmap *clk = to_clk_regmap(hw); + struct device_node *np, *parent_np; + struct device *dev; + + /* Allow regmap to be preset as it was historically done */ + if (clk->map) + return 0; + + /* + * FIXME: what follows couples the controller implementation + * and clk_regmap clock type. This situation is not desirable + * but temporary, until the controller is able to register + * a hook to initialize a clock type + */ + + /* Check the usual dev enabled controller with an basic IO regmap */ + dev = clk_hw_get_dev(hw); + if (dev) { + clk->map = dev_get_regmap(dev, NULL); + if (clk->map) + return 0; + } + + /* Move on to early and syscon based controllers */ + np = clk_hw_get_of_node(hw); + if (np) { + parent_np = of_get_parent(np); + clk->map = syscon_node_to_regmap(parent_np); + of_node_put(parent_np); + + if (!IS_ERR_OR_NULL(clk->map)) + return 0; + } + + /* Bail out if regmap can't be found */ + return -EINVAL; +} +EXPORT_SYMBOL_NS_GPL(clk_regmap_init, "CLK_MESON"); + static int clk_regmap_gate_endisable(struct clk_hw *hw, int enable) { struct clk_regmap *clk = to_clk_regmap(hw); @@ -45,16 +88,18 @@ static int clk_regmap_gate_is_enabled(struct clk_hw *hw) } const struct clk_ops clk_regmap_gate_ops = { + .init = clk_regmap_init, .enable = clk_regmap_gate_enable, .disable = clk_regmap_gate_disable, .is_enabled = clk_regmap_gate_is_enabled, }; -EXPORT_SYMBOL_NS_GPL(clk_regmap_gate_ops, CLK_MESON); +EXPORT_SYMBOL_NS_GPL(clk_regmap_gate_ops, "CLK_MESON"); const struct clk_ops clk_regmap_gate_ro_ops = { + .init = clk_regmap_init, .is_enabled = clk_regmap_gate_is_enabled, }; -EXPORT_SYMBOL_NS_GPL(clk_regmap_gate_ro_ops, CLK_MESON); +EXPORT_SYMBOL_NS_GPL(clk_regmap_gate_ro_ops, "CLK_MESON"); static unsigned long clk_regmap_div_recalc_rate(struct clk_hw *hw, unsigned long prate) @@ -121,17 +166,19 @@ static int clk_regmap_div_set_rate(struct clk_hw *hw, unsigned long rate, /* Would prefer clk_regmap_div_ro_ops but clashes with qcom */ const struct clk_ops clk_regmap_divider_ops = { + .init = clk_regmap_init, .recalc_rate = clk_regmap_div_recalc_rate, .determine_rate = clk_regmap_div_determine_rate, .set_rate = clk_regmap_div_set_rate, }; -EXPORT_SYMBOL_NS_GPL(clk_regmap_divider_ops, CLK_MESON); +EXPORT_SYMBOL_NS_GPL(clk_regmap_divider_ops, "CLK_MESON"); const struct clk_ops clk_regmap_divider_ro_ops = { + .init = clk_regmap_init, .recalc_rate = clk_regmap_div_recalc_rate, .determine_rate = clk_regmap_div_determine_rate, }; -EXPORT_SYMBOL_NS_GPL(clk_regmap_divider_ro_ops, CLK_MESON); +EXPORT_SYMBOL_NS_GPL(clk_regmap_divider_ro_ops, "CLK_MESON"); static u8 clk_regmap_mux_get_parent(struct clk_hw *hw) { @@ -170,18 +217,20 @@ static int clk_regmap_mux_determine_rate(struct clk_hw *hw, } const struct clk_ops clk_regmap_mux_ops = { + .init = clk_regmap_init, .get_parent = clk_regmap_mux_get_parent, .set_parent = clk_regmap_mux_set_parent, .determine_rate = clk_regmap_mux_determine_rate, }; -EXPORT_SYMBOL_NS_GPL(clk_regmap_mux_ops, CLK_MESON); +EXPORT_SYMBOL_NS_GPL(clk_regmap_mux_ops, "CLK_MESON"); const struct clk_ops clk_regmap_mux_ro_ops = { + .init = clk_regmap_init, .get_parent = clk_regmap_mux_get_parent, }; -EXPORT_SYMBOL_NS_GPL(clk_regmap_mux_ro_ops, CLK_MESON); +EXPORT_SYMBOL_NS_GPL(clk_regmap_mux_ro_ops, "CLK_MESON"); MODULE_DESCRIPTION("Amlogic regmap backed clock driver"); MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(CLK_MESON); +MODULE_IMPORT_NS("CLK_MESON"); |
