diff options
Diffstat (limited to 'drivers/clk/mediatek/clk-mtk.c')
-rw-r--r-- | drivers/clk/mediatek/clk-mtk.c | 136 |
1 files changed, 123 insertions, 13 deletions
diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c index 3c1ac8d3010f..14e8b64a32a3 100644 --- a/drivers/clk/mediatek/clk-mtk.c +++ b/drivers/clk/mediatek/clk-mtk.c @@ -11,12 +11,30 @@ #include <linux/mfd/syscon.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_address.h> #include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/slab.h> #include "clk-mtk.h" #include "clk-gate.h" +#include "clk-mux.h" + +const struct mtk_gate_regs cg_regs_dummy = { 0, 0, 0 }; +EXPORT_SYMBOL_GPL(cg_regs_dummy); + +static int mtk_clk_dummy_enable(struct clk_hw *hw) +{ + return 0; +} + +static void mtk_clk_dummy_disable(struct clk_hw *hw) { } + +const struct clk_ops mtk_clk_dummy_ops = { + .enable = mtk_clk_dummy_enable, + .disable = mtk_clk_dummy_disable, +}; +EXPORT_SYMBOL_GPL(mtk_clk_dummy_ops); static void mtk_init_clk_data(struct clk_hw_onecell_data *clk_data, unsigned int clk_num) @@ -197,8 +215,8 @@ void mtk_clk_unregister_factors(const struct mtk_fixed_factor *clks, int num, } EXPORT_SYMBOL_GPL(mtk_clk_unregister_factors); -static struct clk_hw *mtk_clk_register_composite(const struct mtk_composite *mc, - void __iomem *base, spinlock_t *lock) +static struct clk_hw *mtk_clk_register_composite(struct device *dev, + const struct mtk_composite *mc, void __iomem *base, spinlock_t *lock) { struct clk_hw *hw; struct clk_mux *mux = NULL; @@ -264,7 +282,7 @@ static struct clk_hw *mtk_clk_register_composite(const struct mtk_composite *mc, div_ops = &clk_divider_ops; } - hw = clk_hw_register_composite(NULL, mc->name, parent_names, num_parents, + hw = clk_hw_register_composite(dev, mc->name, parent_names, num_parents, mux_hw, mux_ops, div_hw, div_ops, gate_hw, gate_ops, @@ -308,7 +326,8 @@ static void mtk_clk_unregister_composite(struct clk_hw *hw) kfree(mux); } -int mtk_clk_register_composites(const struct mtk_composite *mcs, int num, +int mtk_clk_register_composites(struct device *dev, + const struct mtk_composite *mcs, int num, void __iomem *base, spinlock_t *lock, struct clk_hw_onecell_data *clk_data) { @@ -327,7 +346,7 @@ int mtk_clk_register_composites(const struct mtk_composite *mcs, int num, continue; } - hw = mtk_clk_register_composite(mc, base, lock); + hw = mtk_clk_register_composite(dev, mc, base, lock); if (IS_ERR(hw)) { pr_err("Failed to register clk %s: %pe\n", mc->name, @@ -449,20 +468,79 @@ int mtk_clk_simple_probe(struct platform_device *pdev) const struct mtk_clk_desc *mcd; struct clk_hw_onecell_data *clk_data; struct device_node *node = pdev->dev.of_node; - int r; + void __iomem *base; + int num_clks, r; mcd = of_device_get_match_data(&pdev->dev); if (!mcd) return -EINVAL; - clk_data = mtk_alloc_clk_data(mcd->num_clks); + /* Composite clocks needs us to pass iomem pointer */ + if (mcd->composite_clks) { + if (!mcd->shared_io) + base = devm_platform_ioremap_resource(pdev, 0); + else + base = of_iomap(node, 0); + + if (IS_ERR_OR_NULL(base)) + return IS_ERR(base) ? PTR_ERR(base) : -ENOMEM; + } + + /* Calculate how many clk_hw_onecell_data entries to allocate */ + num_clks = mcd->num_clks + mcd->num_composite_clks; + num_clks += mcd->num_fixed_clks + mcd->num_factor_clks; + num_clks += mcd->num_mux_clks; + + clk_data = mtk_alloc_clk_data(num_clks); if (!clk_data) return -ENOMEM; - r = mtk_clk_register_gates_with_dev(node, mcd->clks, mcd->num_clks, - clk_data, &pdev->dev); - if (r) - goto free_data; + if (mcd->fixed_clks) { + r = mtk_clk_register_fixed_clks(mcd->fixed_clks, + mcd->num_fixed_clks, clk_data); + if (r) + goto free_data; + } + + if (mcd->factor_clks) { + r = mtk_clk_register_factors(mcd->factor_clks, + mcd->num_factor_clks, clk_data); + if (r) + goto unregister_fixed_clks; + } + + if (mcd->mux_clks) { + r = mtk_clk_register_muxes(&pdev->dev, mcd->mux_clks, + mcd->num_mux_clks, node, + mcd->clk_lock, clk_data); + if (r) + goto unregister_factors; + } + + if (mcd->composite_clks) { + /* We don't check composite_lock because it's optional */ + r = mtk_clk_register_composites(&pdev->dev, + mcd->composite_clks, + mcd->num_composite_clks, + base, mcd->clk_lock, clk_data); + if (r) + goto unregister_muxes; + } + + if (mcd->clks) { + r = mtk_clk_register_gates(&pdev->dev, node, mcd->clks, + mcd->num_clks, clk_data); + if (r) + goto unregister_composites; + } + + if (mcd->clk_notifier_func) { + struct clk *mfg_mux = clk_data->hws[mcd->mfg_clk_idx]->clk; + + r = mcd->clk_notifier_func(&pdev->dev, mfg_mux); + if (r) + goto unregister_clks; + } r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); if (r) @@ -480,9 +558,28 @@ int mtk_clk_simple_probe(struct platform_device *pdev) return r; unregister_clks: - mtk_clk_unregister_gates(mcd->clks, mcd->num_clks, clk_data); + if (mcd->clks) + mtk_clk_unregister_gates(mcd->clks, mcd->num_clks, clk_data); +unregister_composites: + if (mcd->composite_clks) + mtk_clk_unregister_composites(mcd->composite_clks, + mcd->num_composite_clks, clk_data); +unregister_muxes: + if (mcd->mux_clks) + mtk_clk_unregister_muxes(mcd->mux_clks, + mcd->num_mux_clks, clk_data); +unregister_factors: + if (mcd->factor_clks) + mtk_clk_unregister_factors(mcd->factor_clks, + mcd->num_factor_clks, clk_data); +unregister_fixed_clks: + if (mcd->fixed_clks) + mtk_clk_unregister_fixed_clks(mcd->fixed_clks, + mcd->num_fixed_clks, clk_data); free_data: mtk_free_clk_data(clk_data); + if (mcd->shared_io && base) + iounmap(base); return r; } EXPORT_SYMBOL_GPL(mtk_clk_simple_probe); @@ -494,7 +591,20 @@ int mtk_clk_simple_remove(struct platform_device *pdev) struct device_node *node = pdev->dev.of_node; of_clk_del_provider(node); - mtk_clk_unregister_gates(mcd->clks, mcd->num_clks, clk_data); + if (mcd->clks) + mtk_clk_unregister_gates(mcd->clks, mcd->num_clks, clk_data); + if (mcd->composite_clks) + mtk_clk_unregister_composites(mcd->composite_clks, + mcd->num_composite_clks, clk_data); + if (mcd->mux_clks) + mtk_clk_unregister_muxes(mcd->mux_clks, + mcd->num_mux_clks, clk_data); + if (mcd->factor_clks) + mtk_clk_unregister_factors(mcd->factor_clks, + mcd->num_factor_clks, clk_data); + if (mcd->fixed_clks) + mtk_clk_unregister_fixed_clks(mcd->fixed_clks, + mcd->num_fixed_clks, clk_data); mtk_free_clk_data(clk_data); return 0; |