diff options
Diffstat (limited to 'drivers/clk/mediatek')
45 files changed, 933 insertions, 298 deletions
diff --git a/drivers/clk/mediatek/clk-apmixed.c b/drivers/clk/mediatek/clk-apmixed.c index caa9119413f1..a29339cc26c4 100644 --- a/drivers/clk/mediatek/clk-apmixed.c +++ b/drivers/clk/mediatek/clk-apmixed.c @@ -92,7 +92,7 @@ struct clk * __init mtk_clk_register_ref2usb_tx(const char *name, clk = clk_register(NULL, &tx->hw); if (IS_ERR(clk)) { - pr_err("Failed to register clk %s: %ld\n", name, PTR_ERR(clk)); + pr_err("Failed to register clk %s: %pe\n", name, clk); kfree(tx); } diff --git a/drivers/clk/mediatek/clk-cpumux.c b/drivers/clk/mediatek/clk-cpumux.c index e188018bc906..c11b3fae622e 100644 --- a/drivers/clk/mediatek/clk-cpumux.c +++ b/drivers/clk/mediatek/clk-cpumux.c @@ -5,13 +5,24 @@ */ #include <linux/clk-provider.h> +#include <linux/container_of.h> +#include <linux/err.h> #include <linux/mfd/syscon.h> #include <linux/module.h> +#include <linux/regmap.h> #include <linux/slab.h> #include "clk-mtk.h" #include "clk-cpumux.h" +struct mtk_clk_cpumux { + struct clk_hw hw; + struct regmap *regmap; + u32 reg; + u32 mask; + u8 shift; +}; + static inline struct mtk_clk_cpumux *to_mtk_clk_cpumux(struct clk_hw *_hw) { return container_of(_hw, struct mtk_clk_cpumux, hw); @@ -77,6 +88,21 @@ mtk_clk_register_cpumux(const struct mtk_composite *mux, return clk; } +static void mtk_clk_unregister_cpumux(struct clk *clk) +{ + struct mtk_clk_cpumux *cpumux; + struct clk_hw *hw; + + hw = __clk_get_hw(clk); + if (!hw) + return; + + cpumux = to_mtk_clk_cpumux(hw); + + clk_unregister(clk); + kfree(cpumux); +} + int mtk_clk_register_cpumuxes(struct device_node *node, const struct mtk_composite *clks, int num, struct clk_onecell_data *clk_data) @@ -87,25 +113,58 @@ int mtk_clk_register_cpumuxes(struct device_node *node, regmap = device_node_to_regmap(node); if (IS_ERR(regmap)) { - pr_err("Cannot find regmap for %pOF: %ld\n", node, - PTR_ERR(regmap)); + pr_err("Cannot find regmap for %pOF: %pe\n", node, regmap); return PTR_ERR(regmap); } for (i = 0; i < num; i++) { const struct mtk_composite *mux = &clks[i]; + if (!IS_ERR_OR_NULL(clk_data->clks[mux->id])) { + pr_warn("%pOF: Trying to register duplicate clock ID: %d\n", + node, mux->id); + continue; + } + clk = mtk_clk_register_cpumux(mux, regmap); if (IS_ERR(clk)) { - pr_err("Failed to register clk %s: %ld\n", - mux->name, PTR_ERR(clk)); - continue; + pr_err("Failed to register clk %s: %pe\n", mux->name, clk); + goto err; } clk_data->clks[mux->id] = clk; } return 0; + +err: + while (--i >= 0) { + const struct mtk_composite *mux = &clks[i]; + + if (IS_ERR_OR_NULL(clk_data->clks[mux->id])) + continue; + + mtk_clk_unregister_cpumux(clk_data->clks[mux->id]); + clk_data->clks[mux->id] = ERR_PTR(-ENOENT); + } + + return PTR_ERR(clk); +} + +void mtk_clk_unregister_cpumuxes(const struct mtk_composite *clks, int num, + struct clk_onecell_data *clk_data) +{ + int i; + + for (i = num; i > 0; i--) { + const struct mtk_composite *mux = &clks[i - 1]; + + if (IS_ERR_OR_NULL(clk_data->clks[mux->id])) + continue; + + mtk_clk_unregister_cpumux(clk_data->clks[mux->id]); + clk_data->clks[mux->id] = ERR_PTR(-ENOENT); + } } MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-cpumux.h b/drivers/clk/mediatek/clk-cpumux.h index 2aaf1afd4e5f..b07e89f7c283 100644 --- a/drivers/clk/mediatek/clk-cpumux.h +++ b/drivers/clk/mediatek/clk-cpumux.h @@ -7,16 +7,15 @@ #ifndef __DRV_CLK_CPUMUX_H #define __DRV_CLK_CPUMUX_H -struct mtk_clk_cpumux { - struct clk_hw hw; - struct regmap *regmap; - u32 reg; - u32 mask; - u8 shift; -}; +struct clk_onecell_data; +struct device_node; +struct mtk_composite; int mtk_clk_register_cpumuxes(struct device_node *node, const struct mtk_composite *clks, int num, struct clk_onecell_data *clk_data); +void mtk_clk_unregister_cpumuxes(const struct mtk_composite *clks, int num, + struct clk_onecell_data *clk_data); + #endif /* __DRV_CLK_CPUMUX_H */ diff --git a/drivers/clk/mediatek/clk-gate.c b/drivers/clk/mediatek/clk-gate.c index 5d88b428565b..da52023f8455 100644 --- a/drivers/clk/mediatek/clk-gate.c +++ b/drivers/clk/mediatek/clk-gate.c @@ -4,18 +4,30 @@ * Author: James Liao <jamesjj.liao@mediatek.com> */ -#include <linux/of.h> -#include <linux/of_address.h> - -#include <linux/io.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include <linux/clkdev.h> +#include <linux/clk-provider.h> +#include <linux/mfd/syscon.h> #include <linux/module.h> +#include <linux/printk.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include <linux/types.h> -#include "clk-mtk.h" #include "clk-gate.h" +struct mtk_clk_gate { + struct clk_hw hw; + struct regmap *regmap; + int set_ofs; + int clr_ofs; + int sta_ofs; + u8 bit; +}; + +static inline struct mtk_clk_gate *to_mtk_clk_gate(struct clk_hw *hw) +{ + return container_of(hw, struct mtk_clk_gate, hw); +} + static u32 mtk_get_clockgating(struct clk_hw *hw) { struct mtk_clk_gate *cg = to_mtk_clk_gate(hw); @@ -140,17 +152,12 @@ const struct clk_ops mtk_clk_gate_ops_no_setclr_inv = { }; EXPORT_SYMBOL_GPL(mtk_clk_gate_ops_no_setclr_inv); -struct clk *mtk_clk_register_gate( - const char *name, - const char *parent_name, - struct regmap *regmap, - int set_ofs, - int clr_ofs, - int sta_ofs, - u8 bit, - const struct clk_ops *ops, - unsigned long flags, - struct device *dev) +static struct clk *mtk_clk_register_gate(const char *name, + const char *parent_name, + struct regmap *regmap, int set_ofs, + int clr_ofs, int sta_ofs, u8 bit, + const struct clk_ops *ops, + unsigned long flags, struct device *dev) { struct mtk_clk_gate *cg; struct clk *clk; @@ -180,6 +187,107 @@ struct clk *mtk_clk_register_gate( return clk; } -EXPORT_SYMBOL_GPL(mtk_clk_register_gate); + +static void mtk_clk_unregister_gate(struct clk *clk) +{ + struct mtk_clk_gate *cg; + struct clk_hw *hw; + + hw = __clk_get_hw(clk); + if (!hw) + return; + + cg = to_mtk_clk_gate(hw); + + clk_unregister(clk); + kfree(cg); +} + +int mtk_clk_register_gates_with_dev(struct device_node *node, + const struct mtk_gate *clks, int num, + struct clk_onecell_data *clk_data, + struct device *dev) +{ + int i; + struct clk *clk; + struct regmap *regmap; + + if (!clk_data) + return -ENOMEM; + + regmap = device_node_to_regmap(node); + if (IS_ERR(regmap)) { + pr_err("Cannot find regmap for %pOF: %pe\n", node, regmap); + return PTR_ERR(regmap); + } + + for (i = 0; i < num; i++) { + const struct mtk_gate *gate = &clks[i]; + + if (!IS_ERR_OR_NULL(clk_data->clks[gate->id])) { + pr_warn("%pOF: Trying to register duplicate clock ID: %d\n", + node, gate->id); + continue; + } + + clk = mtk_clk_register_gate(gate->name, gate->parent_name, + regmap, + gate->regs->set_ofs, + gate->regs->clr_ofs, + gate->regs->sta_ofs, + gate->shift, gate->ops, + gate->flags, dev); + + if (IS_ERR(clk)) { + pr_err("Failed to register clk %s: %pe\n", gate->name, clk); + goto err; + } + + clk_data->clks[gate->id] = clk; + } + + return 0; + +err: + while (--i >= 0) { + const struct mtk_gate *gate = &clks[i]; + + if (IS_ERR_OR_NULL(clk_data->clks[gate->id])) + continue; + + mtk_clk_unregister_gate(clk_data->clks[gate->id]); + clk_data->clks[gate->id] = ERR_PTR(-ENOENT); + } + + return PTR_ERR(clk); +} + +int mtk_clk_register_gates(struct device_node *node, + const struct mtk_gate *clks, int num, + struct clk_onecell_data *clk_data) +{ + return mtk_clk_register_gates_with_dev(node, clks, num, clk_data, NULL); +} +EXPORT_SYMBOL_GPL(mtk_clk_register_gates); + +void mtk_clk_unregister_gates(const struct mtk_gate *clks, int num, + struct clk_onecell_data *clk_data) +{ + int i; + + if (!clk_data) + return; + + for (i = num; i > 0; i--) { + const struct mtk_gate *gate = &clks[i - 1]; + + if (IS_ERR_OR_NULL(clk_data->clks[gate->id])) + continue; + + mtk_clk_unregister_gate(clk_data->clks[gate->id]); + clk_data->clks[gate->id] = ERR_PTR(-ENOENT); + } +} +EXPORT_SYMBOL_GPL(mtk_clk_unregister_gates); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-gate.h b/drivers/clk/mediatek/clk-gate.h index 3c3329ec54b7..6b5738826a22 100644 --- a/drivers/clk/mediatek/clk-gate.h +++ b/drivers/clk/mediatek/clk-gate.h @@ -7,41 +7,34 @@ #ifndef __DRV_CLK_GATE_H #define __DRV_CLK_GATE_H -#include <linux/regmap.h> -#include <linux/clk-provider.h> +#include <linux/types.h> struct clk; - -struct mtk_clk_gate { - struct clk_hw hw; - struct regmap *regmap; - int set_ofs; - int clr_ofs; - int sta_ofs; - u8 bit; -}; - -static inline struct mtk_clk_gate *to_mtk_clk_gate(struct clk_hw *hw) -{ - return container_of(hw, struct mtk_clk_gate, hw); -} +struct clk_onecell_data; +struct clk_ops; +struct device; +struct device_node; extern const struct clk_ops mtk_clk_gate_ops_setclr; extern const struct clk_ops mtk_clk_gate_ops_setclr_inv; extern const struct clk_ops mtk_clk_gate_ops_no_setclr; extern const struct clk_ops mtk_clk_gate_ops_no_setclr_inv; -struct clk *mtk_clk_register_gate( - const char *name, - const char *parent_name, - struct regmap *regmap, - int set_ofs, - int clr_ofs, - int sta_ofs, - u8 bit, - const struct clk_ops *ops, - unsigned long flags, - struct device *dev); +struct mtk_gate_regs { + u32 sta_ofs; + u32 clr_ofs; + u32 set_ofs; +}; + +struct mtk_gate { + int id; + const char *name; + const char *parent_name; + const struct mtk_gate_regs *regs; + int shift; + const struct clk_ops *ops; + unsigned long flags; +}; #define GATE_MTK_FLAGS(_id, _name, _parent, _regs, _shift, \ _ops, _flags) { \ @@ -57,4 +50,16 @@ struct clk *mtk_clk_register_gate( #define GATE_MTK(_id, _name, _parent, _regs, _shift, _ops) \ GATE_MTK_FLAGS(_id, _name, _parent, _regs, _shift, _ops, 0) +int mtk_clk_register_gates(struct device_node *node, + const struct mtk_gate *clks, int num, + struct clk_onecell_data *clk_data); + +int mtk_clk_register_gates_with_dev(struct device_node *node, + const struct mtk_gate *clks, int num, + struct clk_onecell_data *clk_data, + struct device *dev); + +void mtk_clk_unregister_gates(const struct mtk_gate *clks, int num, + struct clk_onecell_data *clk_data); + #endif /* __DRV_CLK_GATE_H */ diff --git a/drivers/clk/mediatek/clk-mt2701.c b/drivers/clk/mediatek/clk-mt2701.c index 695be0f77427..1eb3e4563c3f 100644 --- a/drivers/clk/mediatek/clk-mt2701.c +++ b/drivers/clk/mediatek/clk-mt2701.c @@ -10,9 +10,10 @@ #include <linux/of_device.h> #include <linux/platform_device.h> -#include "clk-mtk.h" -#include "clk-gate.h" #include "clk-cpumux.h" +#include "clk-gate.h" +#include "clk-mtk.h" +#include "clk-pll.h" #include <dt-bindings/clock/mt2701-clk.h> diff --git a/drivers/clk/mediatek/clk-mt2712.c b/drivers/clk/mediatek/clk-mt2712.c index a3bd9a107209..ff72b9ab945b 100644 --- a/drivers/clk/mediatek/clk-mt2712.c +++ b/drivers/clk/mediatek/clk-mt2712.c @@ -13,8 +13,9 @@ #include <linux/platform_device.h> #include <linux/slab.h> -#include "clk-mtk.h" #include "clk-gate.h" +#include "clk-pll.h" +#include "clk-mtk.h" #include <dt-bindings/clock/mt2712-clk.h> diff --git a/drivers/clk/mediatek/clk-mt6765.c b/drivers/clk/mediatek/clk-mt6765.c index d77ea5aff292..24829ca3bd1f 100644 --- a/drivers/clk/mediatek/clk-mt6765.c +++ b/drivers/clk/mediatek/clk-mt6765.c @@ -12,9 +12,10 @@ #include <linux/of_device.h> #include <linux/platform_device.h> -#include "clk-mtk.h" #include "clk-gate.h" +#include "clk-mtk.h" #include "clk-mux.h" +#include "clk-pll.h" #include <dt-bindings/clock/mt6765-clk.h> diff --git a/drivers/clk/mediatek/clk-mt6779.c b/drivers/clk/mediatek/clk-mt6779.c index 9825385c9f94..7b61664da18f 100644 --- a/drivers/clk/mediatek/clk-mt6779.c +++ b/drivers/clk/mediatek/clk-mt6779.c @@ -10,9 +10,10 @@ #include <linux/of_device.h> #include <linux/platform_device.h> +#include "clk-gate.h" #include "clk-mtk.h" #include "clk-mux.h" -#include "clk-gate.h" +#include "clk-pll.h" #include <dt-bindings/clock/mt6779-clk.h> diff --git a/drivers/clk/mediatek/clk-mt6797.c b/drivers/clk/mediatek/clk-mt6797.c index 428eb24ffec5..02259e81625a 100644 --- a/drivers/clk/mediatek/clk-mt6797.c +++ b/drivers/clk/mediatek/clk-mt6797.c @@ -9,8 +9,9 @@ #include <linux/of_device.h> #include <linux/platform_device.h> -#include "clk-mtk.h" #include "clk-gate.h" +#include "clk-mtk.h" +#include "clk-pll.h" #include <dt-bindings/clock/mt6797-clk.h> diff --git a/drivers/clk/mediatek/clk-mt7622.c b/drivers/clk/mediatek/clk-mt7622.c index ef5947e15c75..0e1fb30a1e98 100644 --- a/drivers/clk/mediatek/clk-mt7622.c +++ b/drivers/clk/mediatek/clk-mt7622.c @@ -11,9 +11,10 @@ #include <linux/of_device.h> #include <linux/platform_device.h> -#include "clk-mtk.h" -#include "clk-gate.h" #include "clk-cpumux.h" +#include "clk-gate.h" +#include "clk-mtk.h" +#include "clk-pll.h" #include <dt-bindings/clock/mt7622-clk.h> #include <linux/clk.h> /* for consumer */ diff --git a/drivers/clk/mediatek/clk-mt7629.c b/drivers/clk/mediatek/clk-mt7629.c index a0ee079670c7..c0e023bf31eb 100644 --- a/drivers/clk/mediatek/clk-mt7629.c +++ b/drivers/clk/mediatek/clk-mt7629.c @@ -12,9 +12,10 @@ #include <linux/of_device.h> #include <linux/platform_device.h> -#include "clk-mtk.h" -#include "clk-gate.h" #include "clk-cpumux.h" +#include "clk-gate.h" +#include "clk-mtk.h" +#include "clk-pll.h" #include <dt-bindings/clock/mt7629-clk.h> diff --git a/drivers/clk/mediatek/clk-mt7986-apmixed.c b/drivers/clk/mediatek/clk-mt7986-apmixed.c index 98ec3887585f..21d4c82e782a 100644 --- a/drivers/clk/mediatek/clk-mt7986-apmixed.c +++ b/drivers/clk/mediatek/clk-mt7986-apmixed.c @@ -10,9 +10,11 @@ #include <linux/of_address.h> #include <linux/of_device.h> #include <linux/platform_device.h> -#include "clk-mtk.h" + #include "clk-gate.h" +#include "clk-mtk.h" #include "clk-mux.h" +#include "clk-pll.h" #include <dt-bindings/clock/mt7986-clk.h> #include <linux/clk.h> diff --git a/drivers/clk/mediatek/clk-mt8135.c b/drivers/clk/mediatek/clk-mt8135.c index 9b4b645aea99..09ad272d51f1 100644 --- a/drivers/clk/mediatek/clk-mt8135.c +++ b/drivers/clk/mediatek/clk-mt8135.c @@ -11,8 +11,9 @@ #include <linux/mfd/syscon.h> #include <dt-bindings/clock/mt8135-clk.h> -#include "clk-mtk.h" #include "clk-gate.h" +#include "clk-mtk.h" +#include "clk-pll.h" static DEFINE_SPINLOCK(mt8135_clk_lock); diff --git a/drivers/clk/mediatek/clk-mt8167.c b/drivers/clk/mediatek/clk-mt8167.c index e5ea10e31799..812b33a57530 100644 --- a/drivers/clk/mediatek/clk-mt8167.c +++ b/drivers/clk/mediatek/clk-mt8167.c @@ -12,8 +12,9 @@ #include <linux/slab.h> #include <linux/mfd/syscon.h> -#include "clk-mtk.h" #include "clk-gate.h" +#include "clk-mtk.h" +#include "clk-pll.h" #include <dt-bindings/clock/mt8167-clk.h> diff --git a/drivers/clk/mediatek/clk-mt8173.c b/drivers/clk/mediatek/clk-mt8173.c index 8f898ac476c0..46b7655feeaa 100644 --- a/drivers/clk/mediatek/clk-mt8173.c +++ b/drivers/clk/mediatek/clk-mt8173.c @@ -8,9 +8,10 @@ #include <linux/of.h> #include <linux/of_address.h> -#include "clk-mtk.h" -#include "clk-gate.h" #include "clk-cpumux.h" +#include "clk-gate.h" +#include "clk-mtk.h" +#include "clk-pll.h" #include <dt-bindings/clock/mt8173-clk.h> diff --git a/drivers/clk/mediatek/clk-mt8183.c b/drivers/clk/mediatek/clk-mt8183.c index 5046852eb0fd..68496554dd3d 100644 --- a/drivers/clk/mediatek/clk-mt8183.c +++ b/drivers/clk/mediatek/clk-mt8183.c @@ -11,9 +11,10 @@ #include <linux/platform_device.h> #include <linux/slab.h> +#include "clk-gate.h" #include "clk-mtk.h" #include "clk-mux.h" -#include "clk-gate.h" +#include "clk-pll.h" #include <dt-bindings/clock/mt8183-clk.h> diff --git a/drivers/clk/mediatek/clk-mt8192.c b/drivers/clk/mediatek/clk-mt8192.c index cbc7c6dbe0f4..ab27cd66b866 100644 --- a/drivers/clk/mediatek/clk-mt8192.c +++ b/drivers/clk/mediatek/clk-mt8192.c @@ -12,9 +12,10 @@ #include <linux/platform_device.h> #include <linux/slab.h> +#include "clk-gate.h" #include "clk-mtk.h" #include "clk-mux.h" -#include "clk-gate.h" +#include "clk-pll.h" #include <dt-bindings/clock/mt8192-clk.h> @@ -1236,9 +1237,17 @@ static int clk_mt8192_infra_probe(struct platform_device *pdev) r = mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks), clk_data); if (r) - return r; + goto free_clk_data; + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + if (r) + goto free_clk_data; - return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + return r; + +free_clk_data: + mtk_free_clk_data(clk_data); + return r; } static int clk_mt8192_peri_probe(struct platform_device *pdev) @@ -1253,9 +1262,17 @@ static int clk_mt8192_peri_probe(struct platform_device *pdev) r = mtk_clk_register_gates(node, peri_clks, ARRAY_SIZE(peri_clks), clk_data); if (r) - return r; + goto free_clk_data; + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + if (r) + goto free_clk_data; + + return r; - return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); +free_clk_data: + mtk_free_clk_data(clk_data); + return r; } static int clk_mt8192_apmixed_probe(struct platform_device *pdev) @@ -1271,9 +1288,17 @@ static int clk_mt8192_apmixed_probe(struct platform_device *pdev) mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); r = mtk_clk_register_gates(node, apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data); if (r) - return r; + goto free_clk_data; - return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + if (r) + goto free_clk_data; + + return r; + +free_clk_data: + mtk_free_clk_data(clk_data); + return r; } static const struct of_device_id of_match_clk_mt8192[] = { diff --git a/drivers/clk/mediatek/clk-mt8195-apmixedsys.c b/drivers/clk/mediatek/clk-mt8195-apmixedsys.c index 6156ceeed71e..eecc7035a56a 100644 --- a/drivers/clk/mediatek/clk-mt8195-apmixedsys.c +++ b/drivers/clk/mediatek/clk-mt8195-apmixedsys.c @@ -5,6 +5,7 @@ #include "clk-gate.h" #include "clk-mtk.h" +#include "clk-pll.h" #include <dt-bindings/clock/mt8195-clk.h> #include <linux/of_device.h> @@ -119,24 +120,47 @@ static int clk_mt8195_apmixed_probe(struct platform_device *pdev) if (!clk_data) return -ENOMEM; - mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); - r = mtk_clk_register_gates(node, apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data); + r = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); if (r) goto free_apmixed_data; + r = mtk_clk_register_gates(node, apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data); + if (r) + goto unregister_plls; + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); if (r) - goto free_apmixed_data; + goto unregister_gates; + + platform_set_drvdata(pdev, clk_data); return r; +unregister_gates: + mtk_clk_unregister_gates(apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data); +unregister_plls: + mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data); free_apmixed_data: mtk_free_clk_data(clk_data); return r; } +static int clk_mt8195_apmixed_remove(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct clk_onecell_data *clk_data = platform_get_drvdata(pdev); + + of_clk_del_provider(node); + mtk_clk_unregister_gates(apmixed_clks, ARRAY_SIZE(apmixed_clks), clk_data); + mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data); + mtk_free_clk_data(clk_data); + + return 0; +} + static struct platform_driver clk_mt8195_apmixed_drv = { .probe = clk_mt8195_apmixed_probe, + .remove = clk_mt8195_apmixed_remove, .driver = { .name = "clk-mt8195-apmixed", .of_match_table = of_match_clk_mt8195_apmixed, diff --git a/drivers/clk/mediatek/clk-mt8195-apusys_pll.c b/drivers/clk/mediatek/clk-mt8195-apusys_pll.c index f1c84186346e..8cd88dfc3283 100644 --- a/drivers/clk/mediatek/clk-mt8195-apusys_pll.c +++ b/drivers/clk/mediatek/clk-mt8195-apusys_pll.c @@ -4,6 +4,7 @@ // Author: Chun-Jie Chen <chun-jie.chen@mediatek.com> #include "clk-mtk.h" +#include "clk-pll.h" #include <dt-bindings/clock/mt8195-clk.h> #include <linux/clk-provider.h> @@ -65,18 +66,37 @@ static int clk_mt8195_apusys_pll_probe(struct platform_device *pdev) if (!clk_data) return -ENOMEM; - mtk_clk_register_plls(node, apusys_plls, ARRAY_SIZE(apusys_plls), clk_data); - r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + r = mtk_clk_register_plls(node, apusys_plls, ARRAY_SIZE(apusys_plls), clk_data); if (r) goto free_apusys_pll_data; + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + if (r) + goto unregister_plls; + + platform_set_drvdata(pdev, clk_data); + return r; +unregister_plls: + mtk_clk_unregister_plls(apusys_plls, ARRAY_SIZE(apusys_plls), clk_data); free_apusys_pll_data: mtk_free_clk_data(clk_data); return r; } +static int clk_mt8195_apusys_pll_remove(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data = platform_get_drvdata(pdev); + struct device_node *node = pdev->dev.of_node; + + of_clk_del_provider(node); + mtk_clk_unregister_plls(apusys_plls, ARRAY_SIZE(apusys_plls), clk_data); + mtk_free_clk_data(clk_data); + + return 0; +} + static const struct of_device_id of_match_clk_mt8195_apusys_pll[] = { { .compatible = "mediatek,mt8195-apusys_pll", }, {} @@ -84,6 +104,7 @@ static const struct of_device_id of_match_clk_mt8195_apusys_pll[] = { static struct platform_driver clk_mt8195_apusys_pll_drv = { .probe = clk_mt8195_apusys_pll_probe, + .remove = clk_mt8195_apusys_pll_remove, .driver = { .name = "clk-mt8195-apusys_pll", .of_match_table = of_match_clk_mt8195_apusys_pll, diff --git a/drivers/clk/mediatek/clk-mt8195-cam.c b/drivers/clk/mediatek/clk-mt8195-cam.c index 3d261fc3848e..e4d00fe6e757 100644 --- a/drivers/clk/mediatek/clk-mt8195-cam.c +++ b/drivers/clk/mediatek/clk-mt8195-cam.c @@ -134,6 +134,7 @@ static const struct of_device_id of_match_clk_mt8195_cam[] = { static struct platform_driver clk_mt8195_cam_drv = { .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, .driver = { .name = "clk-mt8195-cam", .of_match_table = of_match_clk_mt8195_cam, diff --git a/drivers/clk/mediatek/clk-mt8195-ccu.c b/drivers/clk/mediatek/clk-mt8195-ccu.c index f846f1d73605..4e326b6301ba 100644 --- a/drivers/clk/mediatek/clk-mt8195-ccu.c +++ b/drivers/clk/mediatek/clk-mt8195-ccu.c @@ -42,6 +42,7 @@ static const struct of_device_id of_match_clk_mt8195_ccu[] = { static struct platform_driver clk_mt8195_ccu_drv = { .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, .driver = { .name = "clk-mt8195-ccu", .of_match_table = of_match_clk_mt8195_ccu, diff --git a/drivers/clk/mediatek/clk-mt8195-img.c b/drivers/clk/mediatek/clk-mt8195-img.c index 22b52a8f15fe..12f5c436d075 100644 --- a/drivers/clk/mediatek/clk-mt8195-img.c +++ b/drivers/clk/mediatek/clk-mt8195-img.c @@ -88,6 +88,7 @@ static const struct of_device_id of_match_clk_mt8195_img[] = { static struct platform_driver clk_mt8195_img_drv = { .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, .driver = { .name = "clk-mt8195-img", .of_match_table = of_match_clk_mt8195_img, diff --git a/drivers/clk/mediatek/clk-mt8195-imp_iic_wrap.c b/drivers/clk/mediatek/clk-mt8195-imp_iic_wrap.c index 4ab312eb26a5..fbc809d05072 100644 --- a/drivers/clk/mediatek/clk-mt8195-imp_iic_wrap.c +++ b/drivers/clk/mediatek/clk-mt8195-imp_iic_wrap.c @@ -58,6 +58,7 @@ static const struct of_device_id of_match_clk_mt8195_imp_iic_wrap[] = { static struct platform_driver clk_mt8195_imp_iic_wrap_drv = { .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, .driver = { .name = "clk-mt8195-imp_iic_wrap", .of_match_table = of_match_clk_mt8195_imp_iic_wrap, diff --git a/drivers/clk/mediatek/clk-mt8195-infra_ao.c b/drivers/clk/mediatek/clk-mt8195-infra_ao.c index 5f9b69967459..8ebe3b9415c4 100644 --- a/drivers/clk/mediatek/clk-mt8195-infra_ao.c +++ b/drivers/clk/mediatek/clk-mt8195-infra_ao.c @@ -198,6 +198,7 @@ static const struct of_device_id of_match_clk_mt8195_infra_ao[] = { static struct platform_driver clk_mt8195_infra_ao_drv = { .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, .driver = { .name = "clk-mt8195-infra_ao", .of_match_table = of_match_clk_mt8195_infra_ao, diff --git a/drivers/clk/mediatek/clk-mt8195-ipe.c b/drivers/clk/mediatek/clk-mt8195-ipe.c index fc1d42b6ac84..b0d745cf7752 100644 --- a/drivers/clk/mediatek/clk-mt8195-ipe.c +++ b/drivers/clk/mediatek/clk-mt8195-ipe.c @@ -43,6 +43,7 @@ static const struct of_device_id of_match_clk_mt8195_ipe[] = { static struct platform_driver clk_mt8195_ipe_drv = { .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, .driver = { .name = "clk-mt8195-ipe", .of_match_table = of_match_clk_mt8195_ipe, diff --git a/drivers/clk/mediatek/clk-mt8195-mfg.c b/drivers/clk/mediatek/clk-mt8195-mfg.c index aca6d9c0837c..9411c556a5a9 100644 --- a/drivers/clk/mediatek/clk-mt8195-mfg.c +++ b/drivers/clk/mediatek/clk-mt8195-mfg.c @@ -39,6 +39,7 @@ static const struct of_device_id of_match_clk_mt8195_mfg[] = { static struct platform_driver clk_mt8195_mfg_drv = { .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, .driver = { .name = "clk-mt8195-mfg", .of_match_table = of_match_clk_mt8195_mfg, diff --git a/drivers/clk/mediatek/clk-mt8195-peri_ao.c b/drivers/clk/mediatek/clk-mt8195-peri_ao.c index 907a92b22de8..2f6b3bb657db 100644 --- a/drivers/clk/mediatek/clk-mt8195-peri_ao.c +++ b/drivers/clk/mediatek/clk-mt8195-peri_ao.c @@ -54,6 +54,7 @@ static const struct of_device_id of_match_clk_mt8195_peri_ao[] = { static struct platform_driver clk_mt8195_peri_ao_drv = { .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, .driver = { .name = "clk-mt8195-peri_ao", .of_match_table = of_match_clk_mt8195_peri_ao, diff --git a/drivers/clk/mediatek/clk-mt8195-scp_adsp.c b/drivers/clk/mediatek/clk-mt8195-scp_adsp.c index 26b4846c5894..e16c383f631b 100644 --- a/drivers/clk/mediatek/clk-mt8195-scp_adsp.c +++ b/drivers/clk/mediatek/clk-mt8195-scp_adsp.c @@ -39,6 +39,7 @@ static const struct of_device_id of_match_clk_mt8195_scp_adsp[] = { static struct platform_driver clk_mt8195_scp_adsp_drv = { .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, .driver = { .name = "clk-mt8195-scp_adsp", .of_match_table = of_match_clk_mt8195_scp_adsp, diff --git a/drivers/clk/mediatek/clk-mt8195-topckgen.c b/drivers/clk/mediatek/clk-mt8195-topckgen.c index 3e2aba9c40bb..b602fcd7f1d1 100644 --- a/drivers/clk/mediatek/clk-mt8195-topckgen.c +++ b/drivers/clk/mediatek/clk-mt8195-topckgen.c @@ -1239,32 +1239,79 @@ static int clk_mt8195_topck_probe(struct platform_device *pdev) goto free_top_data; } - mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks), - top_clk_data); - mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), top_clk_data); - mtk_clk_register_muxes(top_mtk_muxes, ARRAY_SIZE(top_mtk_muxes), node, - &mt8195_clk_lock, top_clk_data); - mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes), base, - &mt8195_clk_lock, top_clk_data); - mtk_clk_register_composites(top_adj_divs, ARRAY_SIZE(top_adj_divs), base, - &mt8195_clk_lock, top_clk_data); - r = mtk_clk_register_gates(node, top_clks, ARRAY_SIZE(top_clks), top_clk_data); + r = mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks), + top_clk_data); if (r) goto free_top_data; + r = mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), top_clk_data); + if (r) + goto unregister_fixed_clks; + + r = mtk_clk_register_muxes(top_mtk_muxes, ARRAY_SIZE(top_mtk_muxes), node, + &mt8195_clk_lock, top_clk_data); + if (r) + goto unregister_factors; + + r = mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes), base, + &mt8195_clk_lock, top_clk_data); + if (r) + goto unregister_muxes; + + r = mtk_clk_register_composites(top_adj_divs, ARRAY_SIZE(top_adj_divs), base, + &mt8195_clk_lock, top_clk_data); + if (r) + goto unregister_composite_muxes; + + r = mtk_clk_register_gates(node, top_clks, ARRAY_SIZE(top_clks), top_clk_data); + if (r) + goto unregister_composite_divs; + r = of_clk_add_provider(node, of_clk_src_onecell_get, top_clk_data); if (r) - goto free_top_data; + goto unregister_gates; + + platform_set_drvdata(pdev, top_clk_data); return r; +unregister_gates: + mtk_clk_unregister_gates(top_clks, ARRAY_SIZE(top_clks), top_clk_data); +unregister_composite_divs: + mtk_clk_unregister_composites(top_adj_divs, ARRAY_SIZE(top_adj_divs), top_clk_data); +unregister_composite_muxes: + mtk_clk_unregister_composites(top_muxes, ARRAY_SIZE(top_muxes), top_clk_data); +unregister_muxes: + mtk_clk_unregister_muxes(top_mtk_muxes, ARRAY_SIZE(top_mtk_muxes), top_clk_data); +unregister_factors: + mtk_clk_unregister_factors(top_divs, ARRAY_SIZE(top_divs), top_clk_data); +unregister_fixed_clks: + mtk_clk_unregister_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks), top_clk_data); free_top_data: mtk_free_clk_data(top_clk_data); return r; } +static int clk_mt8195_topck_remove(struct platform_device *pdev) +{ + struct clk_onecell_data *top_clk_data = platform_get_drvdata(pdev); + struct device_node *node = pdev->dev.of_node; + + of_clk_del_provider(node); + mtk_clk_unregister_gates(top_clks, ARRAY_SIZE(top_clks), top_clk_data); + mtk_clk_unregister_composites(top_adj_divs, ARRAY_SIZE(top_adj_divs), top_clk_data); + mtk_clk_unregister_composites(top_muxes, ARRAY_SIZE(top_muxes), top_clk_data); + mtk_clk_unregister_muxes(top_mtk_muxes, ARRAY_SIZE(top_mtk_muxes), top_clk_data); + mtk_clk_unregister_factors(top_divs, ARRAY_SIZE(top_divs), top_clk_data); + mtk_clk_unregister_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks), top_clk_data); + mtk_free_clk_data(top_clk_data); + + return 0; +} + static struct platform_driver clk_mt8195_topck_drv = { .probe = clk_mt8195_topck_probe, + .remove = clk_mt8195_topck_remove, .driver = { .name = "clk-mt8195-topck", .of_match_table = of_match_clk_mt8195_topck, diff --git a/drivers/clk/mediatek/clk-mt8195-vdec.c b/drivers/clk/mediatek/clk-mt8195-vdec.c index a1df04f42a90..a1446b666385 100644 --- a/drivers/clk/mediatek/clk-mt8195-vdec.c +++ b/drivers/clk/mediatek/clk-mt8195-vdec.c @@ -96,6 +96,7 @@ static const struct of_device_id of_match_clk_mt8195_vdec[] = { static struct platform_driver clk_mt8195_vdec_drv = { .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, .driver = { .name = "clk-mt8195-vdec", .of_match_table = of_match_clk_mt8195_vdec, diff --git a/drivers/clk/mediatek/clk-mt8195-vdo0.c b/drivers/clk/mediatek/clk-mt8195-vdo0.c index f7ff7618c714..3bc7ed19d550 100644 --- a/drivers/clk/mediatek/clk-mt8195-vdo0.c +++ b/drivers/clk/mediatek/clk-mt8195-vdo0.c @@ -105,17 +105,35 @@ static int clk_mt8195_vdo0_probe(struct platform_device *pdev) r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); if (r) - goto free_vdo0_data; + goto unregister_gates; + + platform_set_drvdata(pdev, clk_data); return r; +unregister_gates: + mtk_clk_unregister_gates(vdo0_clks, ARRAY_SIZE(vdo0_clks), clk_data); free_vdo0_data: mtk_free_clk_data(clk_data); return r; } +static int clk_mt8195_vdo0_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *node = dev->parent->of_node; + struct clk_onecell_data *clk_data = platform_get_drvdata(pdev); + + of_clk_del_provider(node); + mtk_clk_unregister_gates(vdo0_clks, ARRAY_SIZE(vdo0_clks), clk_data); + mtk_free_clk_data(clk_data); + + return 0; +} + static struct platform_driver clk_mt8195_vdo0_drv = { .probe = clk_mt8195_vdo0_probe, + .remove = clk_mt8195_vdo0_remove, .driver = { .name = "clk-mt8195-vdo0", }, diff --git a/drivers/clk/mediatek/clk-mt8195-vdo1.c b/drivers/clk/mediatek/clk-mt8195-vdo1.c index 03df8eae8838..90c738a85ff1 100644 --- a/drivers/clk/mediatek/clk-mt8195-vdo1.c +++ b/drivers/clk/mediatek/clk-mt8195-vdo1.c @@ -122,17 +122,35 @@ static int clk_mt8195_vdo1_probe(struct platform_device *pdev) r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); if (r) - goto free_vdo1_data; + goto unregister_gates; + + platform_set_drvdata(pdev, clk_data); return r; +unregister_gates: + mtk_clk_unregister_gates(vdo1_clks, ARRAY_SIZE(vdo1_clks), clk_data); free_vdo1_data: mtk_free_clk_data(clk_data); return r; } +static int clk_mt8195_vdo1_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *node = dev->parent->of_node; + struct clk_onecell_data *clk_data = platform_get_drvdata(pdev); + + of_clk_del_provider(node); + mtk_clk_unregister_gates(vdo1_clks, ARRAY_SIZE(vdo1_clks), clk_data); + mtk_free_clk_data(clk_data); + + return 0; +} + static struct platform_driver clk_mt8195_vdo1_drv = { .probe = clk_mt8195_vdo1_probe, + .remove = clk_mt8195_vdo1_remove, .driver = { .name = "clk-mt8195-vdo1", }, diff --git a/drivers/clk/mediatek/clk-mt8195-venc.c b/drivers/clk/mediatek/clk-mt8195-venc.c index 7339851a0856..622f57804f96 100644 --- a/drivers/clk/mediatek/clk-mt8195-venc.c +++ b/drivers/clk/mediatek/clk-mt8195-venc.c @@ -61,6 +61,7 @@ static const struct of_device_id of_match_clk_mt8195_venc[] = { static struct platform_driver clk_mt8195_venc_drv = { .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, .driver = { .name = "clk-mt8195-venc", .of_match_table = of_match_clk_mt8195_venc, diff --git a/drivers/clk/mediatek/clk-mt8195-vpp0.c b/drivers/clk/mediatek/clk-mt8195-vpp0.c index c3241466a8d0..bf2939c3a023 100644 --- a/drivers/clk/mediatek/clk-mt8195-vpp0.c +++ b/drivers/clk/mediatek/clk-mt8195-vpp0.c @@ -102,6 +102,7 @@ static const struct of_device_id of_match_clk_mt8195_vpp0[] = { static struct platform_driver clk_mt8195_vpp0_drv = { .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, .driver = { .name = "clk-mt8195-vpp0", .of_match_table = of_match_clk_mt8195_vpp0, diff --git a/drivers/clk/mediatek/clk-mt8195-vpp1.c b/drivers/clk/mediatek/clk-mt8195-vpp1.c index ce0b9a40a179..ffd52c762890 100644 --- a/drivers/clk/mediatek/clk-mt8195-vpp1.c +++ b/drivers/clk/mediatek/clk-mt8195-vpp1.c @@ -100,6 +100,7 @@ static const struct of_device_id of_match_clk_mt8195_vpp1[] = { static struct platform_driver clk_mt8195_vpp1_drv = { .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, .driver = { .name = "clk-mt8195-vpp1", .of_match_table = of_match_clk_mt8195_vpp1, diff --git a/drivers/clk/mediatek/clk-mt8195-wpe.c b/drivers/clk/mediatek/clk-mt8195-wpe.c index 274d60838d8e..b483fab10e18 100644 --- a/drivers/clk/mediatek/clk-mt8195-wpe.c +++ b/drivers/clk/mediatek/clk-mt8195-wpe.c @@ -135,6 +135,7 @@ static const struct of_device_id of_match_clk_mt8195_wpe[] = { static struct platform_driver clk_mt8195_wpe_drv = { .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, .driver = { .name = "clk-mt8195-wpe", .of_match_table = of_match_clk_mt8195_wpe, diff --git a/drivers/clk/mediatek/clk-mt8516.c b/drivers/clk/mediatek/clk-mt8516.c index 9d4261ecc760..a37143f920ce 100644 --- a/drivers/clk/mediatek/clk-mt8516.c +++ b/drivers/clk/mediatek/clk-mt8516.c @@ -11,8 +11,9 @@ #include <linux/slab.h> #include <linux/mfd/syscon.h> -#include "clk-mtk.h" #include "clk-gate.h" +#include "clk-mtk.h" +#include "clk-pll.h" #include <dt-bindings/clock/mt8516-clk.h> diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c index 8d5791b3f460..b4063261cf56 100644 --- a/drivers/clk/mediatek/clk-mtk.c +++ b/drivers/clk/mediatek/clk-mtk.c @@ -4,17 +4,16 @@ * Author: James Liao <jamesjj.liao@mediatek.com> */ -#include <linux/of.h> -#include <linux/of_address.h> +#include <linux/bitops.h> +#include <linux/clk-provider.h> #include <linux/err.h> #include <linux/io.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include <linux/clkdev.h> -#include <linux/module.h> #include <linux/mfd/syscon.h> -#include <linux/device.h> +#include <linux/module.h> +#include <linux/of.h> #include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/slab.h> #include "clk-mtk.h" #include "clk-gate.h" @@ -54,112 +53,135 @@ void mtk_free_clk_data(struct clk_onecell_data *clk_data) kfree(clk_data); } -void mtk_clk_register_fixed_clks(const struct mtk_fixed_clk *clks, - int num, struct clk_onecell_data *clk_data) +int mtk_clk_register_fixed_clks(const struct mtk_fixed_clk *clks, int num, + struct clk_onecell_data *clk_data) { int i; struct clk *clk; + if (!clk_data) + return -ENOMEM; + for (i = 0; i < num; i++) { const struct mtk_fixed_clk *rc = &clks[i]; - if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[rc->id])) + if (!IS_ERR_OR_NULL(clk_data->clks[rc->id])) { + pr_warn("Trying to register duplicate clock ID: %d\n", rc->id); continue; + } clk = clk_register_fixed_rate(NULL, rc->name, rc->parent, 0, rc->rate); if (IS_ERR(clk)) { - pr_err("Failed to register clk %s: %ld\n", - rc->name, PTR_ERR(clk)); - continue; + pr_err("Failed to register clk %s: %pe\n", rc->name, clk); + goto err; } - if (clk_data) - clk_data->clks[rc->id] = clk; + clk_data->clks[rc->id] = clk; + } + + return 0; + +err: + while (--i >= 0) { + const struct mtk_fixed_clk *rc = &clks[i]; + + if (IS_ERR_OR_NULL(clk_data->clks[rc->id])) + continue; + + clk_unregister_fixed_rate(clk_data->clks[rc->id]); + clk_data->clks[rc->id] = ERR_PTR(-ENOENT); } + + return PTR_ERR(clk); } EXPORT_SYMBOL_GPL(mtk_clk_register_fixed_clks); -void mtk_clk_register_factors(const struct mtk_fixed_factor *clks, - int num, struct clk_onecell_data *clk_data) +void mtk_clk_unregister_fixed_clks(const struct mtk_fixed_clk *clks, int num, + struct clk_onecell_data *clk_data) { int i; - struct clk *clk; - for (i = 0; i < num; i++) { - const struct mtk_fixed_factor *ff = &clks[i]; - - if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[ff->id])) - continue; + if (!clk_data) + return; - clk = clk_register_fixed_factor(NULL, ff->name, ff->parent_name, - CLK_SET_RATE_PARENT, ff->mult, ff->div); + for (i = num; i > 0; i--) { + const struct mtk_fixed_clk *rc = &clks[i - 1]; - if (IS_ERR(clk)) { - pr_err("Failed to register clk %s: %ld\n", - ff->name, PTR_ERR(clk)); + if (IS_ERR_OR_NULL(clk_data->clks[rc->id])) continue; - } - if (clk_data) - clk_data->clks[ff->id] = clk; + clk_unregister_fixed_rate(clk_data->clks[rc->id]); + clk_data->clks[rc->id] = ERR_PTR(-ENOENT); } } -EXPORT_SYMBOL_GPL(mtk_clk_register_factors); +EXPORT_SYMBOL_GPL(mtk_clk_unregister_fixed_clks); -int mtk_clk_register_gates_with_dev(struct device_node *node, - const struct mtk_gate *clks, - int num, struct clk_onecell_data *clk_data, - struct device *dev) +int mtk_clk_register_factors(const struct mtk_fixed_factor *clks, int num, + struct clk_onecell_data *clk_data) { int i; struct clk *clk; - struct regmap *regmap; if (!clk_data) return -ENOMEM; - regmap = device_node_to_regmap(node); - if (IS_ERR(regmap)) { - pr_err("Cannot find regmap for %pOF: %ld\n", node, - PTR_ERR(regmap)); - return PTR_ERR(regmap); - } - for (i = 0; i < num; i++) { - const struct mtk_gate *gate = &clks[i]; + const struct mtk_fixed_factor *ff = &clks[i]; - if (!IS_ERR_OR_NULL(clk_data->clks[gate->id])) + if (!IS_ERR_OR_NULL(clk_data->clks[ff->id])) { + pr_warn("Trying to register duplicate clock ID: %d\n", ff->id); continue; + } - clk = mtk_clk_register_gate(gate->name, gate->parent_name, - regmap, - gate->regs->set_ofs, - gate->regs->clr_ofs, - gate->regs->sta_ofs, - gate->shift, gate->ops, gate->flags, dev); + clk = clk_register_fixed_factor(NULL, ff->name, ff->parent_name, + CLK_SET_RATE_PARENT, ff->mult, ff->div); if (IS_ERR(clk)) { - pr_err("Failed to register clk %s: %ld\n", - gate->name, PTR_ERR(clk)); - continue; + pr_err("Failed to register clk %s: %pe\n", ff->name, clk); + goto err; } - clk_data->clks[gate->id] = clk; + clk_data->clks[ff->id] = clk; } return 0; + +err: + while (--i >= 0) { + const struct mtk_fixed_factor *ff = &clks[i]; + + if (IS_ERR_OR_NULL(clk_data->clks[ff->id])) + continue; + + clk_unregister_fixed_factor(clk_data->clks[ff->id]); + clk_data->clks[ff->id] = ERR_PTR(-ENOENT); + } + + return PTR_ERR(clk); } +EXPORT_SYMBOL_GPL(mtk_clk_register_factors); -int mtk_clk_register_gates(struct device_node *node, - const struct mtk_gate *clks, - int num, struct clk_onecell_data *clk_data) +void mtk_clk_unregister_factors(const struct mtk_fixed_factor *clks, int num, + struct clk_onecell_data *clk_data) { - return mtk_clk_register_gates_with_dev(node, - clks, num, clk_data, NULL); + int i; + + if (!clk_data) + return; + + for (i = num; i > 0; i--) { + const struct mtk_fixed_factor *ff = &clks[i - 1]; + + if (IS_ERR_OR_NULL(clk_data->clks[ff->id])) + continue; + + clk_unregister_fixed_factor(clk_data->clks[ff->id]); + clk_data->clks[ff->id] = ERR_PTR(-ENOENT); + } } -EXPORT_SYMBOL_GPL(mtk_clk_register_gates); +EXPORT_SYMBOL_GPL(mtk_clk_unregister_factors); struct clk *mtk_clk_register_composite(const struct mtk_composite *mc, void __iomem *base, spinlock_t *lock) @@ -248,58 +270,161 @@ err_out: return ERR_PTR(ret); } -void mtk_clk_register_composites(const struct mtk_composite *mcs, - int num, void __iomem *base, spinlock_t *lock, - struct clk_onecell_data *clk_data) +static void mtk_clk_unregister_composite(struct clk *clk) +{ + struct clk_hw *hw; + struct clk_composite *composite; + struct clk_mux *mux = NULL; + struct clk_gate *gate = NULL; + struct clk_divider *div = NULL; + + hw = __clk_get_hw(clk); + if (!hw) + return; + + composite = to_clk_composite(hw); + if (composite->mux_hw) + mux = to_clk_mux(composite->mux_hw); + if (composite->gate_hw) + gate = to_clk_gate(composite->gate_hw); + if (composite->rate_hw) + div = to_clk_divider(composite->rate_hw); + + clk_unregister_composite(clk); + kfree(div); + kfree(gate); + kfree(mux); +} + +int mtk_clk_register_composites(const struct mtk_composite *mcs, int num, + void __iomem *base, spinlock_t *lock, + struct clk_onecell_data *clk_data) { struct clk *clk; int i; + if (!clk_data) + return -ENOMEM; + for (i = 0; i < num; i++) { const struct mtk_composite *mc = &mcs[i]; - if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[mc->id])) + if (!IS_ERR_OR_NULL(clk_data->clks[mc->id])) { + pr_warn("Trying to register duplicate clock ID: %d\n", + mc->id); continue; + } clk = mtk_clk_register_composite(mc, base, lock); if (IS_ERR(clk)) { - pr_err("Failed to register clk %s: %ld\n", - mc->name, PTR_ERR(clk)); - continue; + pr_err("Failed to register clk %s: %pe\n", mc->name, clk); + goto err; } - if (clk_data) - clk_data->clks[mc->id] = clk; + clk_data->clks[mc->id] = clk; + } + + return 0; + +err: + while (--i >= 0) { + const struct mtk_composite *mc = &mcs[i]; + + if (IS_ERR_OR_NULL(clk_data->clks[mcs->id])) + continue; + + mtk_clk_unregister_composite(clk_data->clks[mc->id]); + clk_data->clks[mc->id] = ERR_PTR(-ENOENT); } + + return PTR_ERR(clk); } EXPORT_SYMBOL_GPL(mtk_clk_register_composites); -void mtk_clk_register_dividers(const struct mtk_clk_divider *mcds, - int num, void __iomem *base, spinlock_t *lock, - struct clk_onecell_data *clk_data) +void mtk_clk_unregister_composites(const struct mtk_composite *mcs, int num, + struct clk_onecell_data *clk_data) +{ + int i; + + if (!clk_data) + return; + + for (i = num; i > 0; i--) { + const struct mtk_composite *mc = &mcs[i - 1]; + + if (IS_ERR_OR_NULL(clk_data->clks[mc->id])) + continue; + + mtk_clk_unregister_composite(clk_data->clks[mc->id]); + clk_data->clks[mc->id] = ERR_PTR(-ENOENT); + } +} +EXPORT_SYMBOL_GPL(mtk_clk_unregister_composites); + +int mtk_clk_register_dividers(const struct mtk_clk_divider *mcds, int num, + void __iomem *base, spinlock_t *lock, + struct clk_onecell_data *clk_data) { struct clk *clk; int i; + if (!clk_data) + return -ENOMEM; + for (i = 0; i < num; i++) { const struct mtk_clk_divider *mcd = &mcds[i]; - if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[mcd->id])) + if (!IS_ERR_OR_NULL(clk_data->clks[mcd->id])) { + pr_warn("Trying to register duplicate clock ID: %d\n", + mcd->id); continue; + } clk = clk_register_divider(NULL, mcd->name, mcd->parent_name, mcd->flags, base + mcd->div_reg, mcd->div_shift, mcd->div_width, mcd->clk_divider_flags, lock); if (IS_ERR(clk)) { - pr_err("Failed to register clk %s: %ld\n", - mcd->name, PTR_ERR(clk)); - continue; + pr_err("Failed to register clk %s: %pe\n", mcd->name, clk); + goto err; } - if (clk_data) - clk_data->clks[mcd->id] = clk; + clk_data->clks[mcd->id] = clk; + } + + return 0; + +err: + while (--i >= 0) { + const struct mtk_clk_divider *mcd = &mcds[i]; + + if (IS_ERR_OR_NULL(clk_data->clks[mcd->id])) + continue; + + mtk_clk_unregister_composite(clk_data->clks[mcd->id]); + clk_data->clks[mcd->id] = ERR_PTR(-ENOENT); + } + + return PTR_ERR(clk); +} + +void mtk_clk_unregister_dividers(const struct mtk_clk_divider *mcds, int num, + struct clk_onecell_data *clk_data) +{ + int i; + + if (!clk_data) + return; + + for (i = num; i > 0; i--) { + const struct mtk_clk_divider *mcd = &mcds[i - 1]; + + if (IS_ERR_OR_NULL(clk_data->clks[mcd->id])) + continue; + + clk_unregister_divider(clk_data->clks[mcd->id]); + clk_data->clks[mcd->id] = ERR_PTR(-ENOENT); } } @@ -324,13 +449,30 @@ int mtk_clk_simple_probe(struct platform_device *pdev) r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); if (r) - goto free_data; + goto unregister_clks; + + platform_set_drvdata(pdev, clk_data); return r; +unregister_clks: + mtk_clk_unregister_gates(mcd->clks, mcd->num_clks, clk_data); free_data: mtk_free_clk_data(clk_data); return r; } +int mtk_clk_simple_remove(struct platform_device *pdev) +{ + const struct mtk_clk_desc *mcd = of_device_get_match_data(&pdev->dev); + struct clk_onecell_data *clk_data = platform_get_drvdata(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); + mtk_free_clk_data(clk_data); + + return 0; +} + MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h index 0ff289d93452..bf6565aa7319 100644 --- a/drivers/clk/mediatek/clk-mtk.h +++ b/drivers/clk/mediatek/clk-mtk.h @@ -7,19 +7,19 @@ #ifndef __DRV_CLK_MTK_H #define __DRV_CLK_MTK_H -#include <linux/regmap.h> -#include <linux/bitops.h> #include <linux/clk-provider.h> -#include <linux/platform_device.h> - -struct clk; -struct clk_onecell_data; +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/spinlock.h> +#include <linux/types.h> #define MAX_MUX_GATE_BIT 31 #define INVALID_MUX_GATE_BIT (MAX_MUX_GATE_BIT + 1) #define MHZ (1000 * 1000) +struct platform_device; + struct mtk_fixed_clk { int id; const char *name; @@ -34,8 +34,10 @@ struct mtk_fixed_clk { .rate = _rate, \ } -void mtk_clk_register_fixed_clks(const struct mtk_fixed_clk *clks, - int num, struct clk_onecell_data *clk_data); +int mtk_clk_register_fixed_clks(const struct mtk_fixed_clk *clks, int num, + struct clk_onecell_data *clk_data); +void mtk_clk_unregister_fixed_clks(const struct mtk_fixed_clk *clks, int num, + struct clk_onecell_data *clk_data); struct mtk_fixed_factor { int id; @@ -53,8 +55,10 @@ struct mtk_fixed_factor { .div = _div, \ } -void mtk_clk_register_factors(const struct mtk_fixed_factor *clks, - int num, struct clk_onecell_data *clk_data); +int mtk_clk_register_factors(const struct mtk_fixed_factor *clks, int num, + struct clk_onecell_data *clk_data); +void mtk_clk_unregister_factors(const struct mtk_fixed_factor *clks, int num, + struct clk_onecell_data *clk_data); struct mtk_composite { int id; @@ -146,34 +150,11 @@ struct mtk_composite { struct clk *mtk_clk_register_composite(const struct mtk_composite *mc, void __iomem *base, spinlock_t *lock); -void mtk_clk_register_composites(const struct mtk_composite *mcs, - int num, void __iomem *base, spinlock_t *lock, - struct clk_onecell_data *clk_data); - -struct mtk_gate_regs { - u32 sta_ofs; - u32 clr_ofs; - u32 set_ofs; -}; - -struct mtk_gate { - int id; - const char *name; - const char *parent_name; - const struct mtk_gate_regs *regs; - int shift; - const struct clk_ops *ops; - unsigned long flags; -}; - -int mtk_clk_register_gates(struct device_node *node, - const struct mtk_gate *clks, int num, - struct clk_onecell_data *clk_data); - -int mtk_clk_register_gates_with_dev(struct device_node *node, - const struct mtk_gate *clks, - int num, struct clk_onecell_data *clk_data, - struct device *dev); +int mtk_clk_register_composites(const struct mtk_composite *mcs, int num, + void __iomem *base, spinlock_t *lock, + struct clk_onecell_data *clk_data); +void mtk_clk_unregister_composites(const struct mtk_composite *mcs, int num, + struct clk_onecell_data *clk_data); struct mtk_clk_divider { int id; @@ -197,52 +178,15 @@ struct mtk_clk_divider { .div_width = _width, \ } -void mtk_clk_register_dividers(const struct mtk_clk_divider *mcds, - int num, void __iomem *base, spinlock_t *lock, - struct clk_onecell_data *clk_data); +int mtk_clk_register_dividers(const struct mtk_clk_divider *mcds, int num, + void __iomem *base, spinlock_t *lock, + struct clk_onecell_data *clk_data); +void mtk_clk_unregister_dividers(const struct mtk_clk_divider *mcds, int num, + struct clk_onecell_data *clk_data); struct clk_onecell_data *mtk_alloc_clk_data(unsigned int clk_num); void mtk_free_clk_data(struct clk_onecell_data *clk_data); -#define HAVE_RST_BAR BIT(0) -#define PLL_AO BIT(1) - -struct mtk_pll_div_table { - u32 div; - unsigned long freq; -}; - -struct mtk_pll_data { - int id; - const char *name; - u32 reg; - u32 pwr_reg; - u32 en_mask; - u32 pd_reg; - u32 tuner_reg; - u32 tuner_en_reg; - u8 tuner_en_bit; - int pd_shift; - unsigned int flags; - const struct clk_ops *ops; - u32 rst_bar_mask; - unsigned long fmin; - unsigned long fmax; - int pcwbits; - int pcwibits; - u32 pcw_reg; - int pcw_shift; - u32 pcw_chg_reg; - const struct mtk_pll_div_table *div_table; - const char *parent_name; - u32 en_reg; - u8 pll_en_bit; /* Assume 0, indicates BIT(0) by default */ -}; - -void mtk_clk_register_plls(struct device_node *node, - const struct mtk_pll_data *plls, int num_plls, - struct clk_onecell_data *clk_data); - struct clk *mtk_clk_register_ref2usb_tx(const char *name, const char *parent_name, void __iomem *reg); @@ -258,5 +202,6 @@ struct mtk_clk_desc { }; int mtk_clk_simple_probe(struct platform_device *pdev); +int mtk_clk_simple_remove(struct platform_device *pdev); #endif /* __DRV_CLK_MTK_H */ diff --git a/drivers/clk/mediatek/clk-mux.c b/drivers/clk/mediatek/clk-mux.c index 6d3a50eb7d6f..21ad5a4afd65 100644 --- a/drivers/clk/mediatek/clk-mux.c +++ b/drivers/clk/mediatek/clk-mux.c @@ -4,15 +4,26 @@ * Author: Owen Chen <owen.chen@mediatek.com> */ -#include <linux/of.h> -#include <linux/of_address.h> -#include <linux/slab.h> +#include <linux/clk-provider.h> +#include <linux/compiler_types.h> +#include <linux/container_of.h> +#include <linux/err.h> #include <linux/mfd/syscon.h> #include <linux/module.h> +#include <linux/regmap.h> +#include <linux/spinlock.h> +#include <linux/slab.h> -#include "clk-mtk.h" #include "clk-mux.h" +struct mtk_clk_mux { + struct clk_hw hw; + struct regmap *regmap; + const struct mtk_mux *data; + spinlock_t *lock; + bool reparent; +}; + static inline struct mtk_clk_mux *to_mtk_clk_mux(struct clk_hw *hw) { return container_of(hw, struct mtk_clk_mux, hw); @@ -164,6 +175,21 @@ static struct clk *mtk_clk_register_mux(const struct mtk_mux *mux, return clk; } +static void mtk_clk_unregister_mux(struct clk *clk) +{ + struct mtk_clk_mux *mux; + struct clk_hw *hw; + + hw = __clk_get_hw(clk); + if (!hw) + return; + + mux = to_mtk_clk_mux(hw); + + clk_unregister(clk); + kfree(mux); +} + int mtk_clk_register_muxes(const struct mtk_mux *muxes, int num, struct device_node *node, spinlock_t *lock, @@ -175,29 +201,64 @@ int mtk_clk_register_muxes(const struct mtk_mux *muxes, regmap = device_node_to_regmap(node); if (IS_ERR(regmap)) { - pr_err("Cannot find regmap for %pOF: %ld\n", node, - PTR_ERR(regmap)); + pr_err("Cannot find regmap for %pOF: %pe\n", node, regmap); return PTR_ERR(regmap); } for (i = 0; i < num; i++) { const struct mtk_mux *mux = &muxes[i]; - if (IS_ERR_OR_NULL(clk_data->clks[mux->id])) { - clk = mtk_clk_register_mux(mux, regmap, lock); + if (!IS_ERR_OR_NULL(clk_data->clks[mux->id])) { + pr_warn("%pOF: Trying to register duplicate clock ID: %d\n", + node, mux->id); + continue; + } - if (IS_ERR(clk)) { - pr_err("Failed to register clk %s: %ld\n", - mux->name, PTR_ERR(clk)); - continue; - } + clk = mtk_clk_register_mux(mux, regmap, lock); - clk_data->clks[mux->id] = clk; + if (IS_ERR(clk)) { + pr_err("Failed to register clk %s: %pe\n", mux->name, clk); + goto err; } + + clk_data->clks[mux->id] = clk; } return 0; + +err: + while (--i >= 0) { + const struct mtk_mux *mux = &muxes[i]; + + if (IS_ERR_OR_NULL(clk_data->clks[mux->id])) + continue; + + mtk_clk_unregister_mux(clk_data->clks[mux->id]); + clk_data->clks[mux->id] = ERR_PTR(-ENOENT); + } + + return PTR_ERR(clk); } EXPORT_SYMBOL_GPL(mtk_clk_register_muxes); +void mtk_clk_unregister_muxes(const struct mtk_mux *muxes, int num, + struct clk_onecell_data *clk_data) +{ + int i; + + if (!clk_data) + return; + + for (i = num; i > 0; i--) { + const struct mtk_mux *mux = &muxes[i - 1]; + + if (IS_ERR_OR_NULL(clk_data->clks[mux->id])) + continue; + + mtk_clk_unregister_mux(clk_data->clks[mux->id]); + clk_data->clks[mux->id] = ERR_PTR(-ENOENT); + } +} +EXPORT_SYMBOL_GPL(mtk_clk_unregister_muxes); + MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mux.h b/drivers/clk/mediatek/clk-mux.h index 27841d649118..903a3c937959 100644 --- a/drivers/clk/mediatek/clk-mux.h +++ b/drivers/clk/mediatek/clk-mux.h @@ -7,15 +7,13 @@ #ifndef __DRV_CLK_MTK_MUX_H #define __DRV_CLK_MTK_MUX_H -#include <linux/clk-provider.h> +#include <linux/spinlock.h> +#include <linux/types.h> -struct mtk_clk_mux { - struct clk_hw hw; - struct regmap *regmap; - const struct mtk_mux *data; - spinlock_t *lock; - bool reparent; -}; +struct clk; +struct clk_onecell_data; +struct clk_ops; +struct device_node; struct mtk_mux { int id; @@ -88,4 +86,7 @@ int mtk_clk_register_muxes(const struct mtk_mux *muxes, spinlock_t *lock, struct clk_onecell_data *clk_data); +void mtk_clk_unregister_muxes(const struct mtk_mux *muxes, int num, + struct clk_onecell_data *clk_data); + #endif /* __DRV_CLK_MTK_MUX_H */ diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c index 60d7ffa0b924..ccaa2085ab4d 100644 --- a/drivers/clk/mediatek/clk-pll.c +++ b/drivers/clk/mediatek/clk-pll.c @@ -4,15 +4,18 @@ * Author: James Liao <jamesjj.liao@mediatek.com> */ -#include <linux/of.h> -#include <linux/of_address.h> +#include <linux/clk-provider.h> +#include <linux/container_of.h> +#include <linux/delay.h> +#include <linux/err.h> #include <linux/io.h> #include <linux/module.h> +#include <linux/of_address.h> #include <linux/slab.h> -#include <linux/clkdev.h> -#include <linux/delay.h> -#include "clk-mtk.h" +#include "clk-pll.h" + +#define MHZ (1000 * 1000) #define REG_CON0 0 #define REG_CON1 4 @@ -359,8 +362,24 @@ static struct clk *mtk_clk_register_pll(const struct mtk_pll_data *data, return clk; } -void mtk_clk_register_plls(struct device_node *node, - const struct mtk_pll_data *plls, int num_plls, struct clk_onecell_data *clk_data) +static void mtk_clk_unregister_pll(struct clk *clk) +{ + struct clk_hw *hw; + struct mtk_clk_pll *pll; + + hw = __clk_get_hw(clk); + if (!hw) + return; + + pll = to_mtk_clk_pll(hw); + + clk_unregister(clk); + kfree(pll); +} + +int mtk_clk_register_plls(struct device_node *node, + const struct mtk_pll_data *plls, int num_plls, + struct clk_onecell_data *clk_data) { void __iomem *base; int i; @@ -369,23 +388,82 @@ void mtk_clk_register_plls(struct device_node *node, base = of_iomap(node, 0); if (!base) { pr_err("%s(): ioremap failed\n", __func__); - return; + return -EINVAL; } for (i = 0; i < num_plls; i++) { const struct mtk_pll_data *pll = &plls[i]; + if (!IS_ERR_OR_NULL(clk_data->clks[pll->id])) { + pr_warn("%pOF: Trying to register duplicate clock ID: %d\n", + node, pll->id); + continue; + } + clk = mtk_clk_register_pll(pll, base); if (IS_ERR(clk)) { - pr_err("Failed to register clk %s: %ld\n", - pll->name, PTR_ERR(clk)); - continue; + pr_err("Failed to register clk %s: %pe\n", pll->name, clk); + goto err; } clk_data->clks[pll->id] = clk; } + + return 0; + +err: + while (--i >= 0) { + const struct mtk_pll_data *pll = &plls[i]; + + mtk_clk_unregister_pll(clk_data->clks[pll->id]); + clk_data->clks[pll->id] = ERR_PTR(-ENOENT); + } + + iounmap(base); + + return PTR_ERR(clk); } EXPORT_SYMBOL_GPL(mtk_clk_register_plls); +static __iomem void *mtk_clk_pll_get_base(struct clk *clk, + const struct mtk_pll_data *data) +{ + struct clk_hw *hw = __clk_get_hw(clk); + struct mtk_clk_pll *pll = to_mtk_clk_pll(hw); + + return pll->base_addr - data->reg; +} + +void mtk_clk_unregister_plls(const struct mtk_pll_data *plls, int num_plls, + struct clk_onecell_data *clk_data) +{ + __iomem void *base = NULL; + int i; + + if (!clk_data) + return; + + for (i = num_plls; i > 0; i--) { + const struct mtk_pll_data *pll = &plls[i - 1]; + + if (IS_ERR_OR_NULL(clk_data->clks[pll->id])) + continue; + + /* + * This is quite ugly but unfortunately the clks don't have + * any device tied to them, so there's no place to store the + * pointer to the I/O region base address. We have to fetch + * it from one of the registered clks. + */ + base = mtk_clk_pll_get_base(clk_data->clks[pll->id], pll); + + mtk_clk_unregister_pll(clk_data->clks[pll->id]); + clk_data->clks[pll->id] = ERR_PTR(-ENOENT); + } + + iounmap(base); +} +EXPORT_SYMBOL_GPL(mtk_clk_unregister_plls); + MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-pll.h b/drivers/clk/mediatek/clk-pll.h new file mode 100644 index 000000000000..bf06e44caef9 --- /dev/null +++ b/drivers/clk/mediatek/clk-pll.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2014 MediaTek Inc. + * Author: James Liao <jamesjj.liao@mediatek.com> + */ + +#ifndef __DRV_CLK_MTK_PLL_H +#define __DRV_CLK_MTK_PLL_H + +#include <linux/types.h> + +struct clk_ops; +struct clk_onecell_data; +struct device_node; + +struct mtk_pll_div_table { + u32 div; + unsigned long freq; +}; + +#define HAVE_RST_BAR BIT(0) +#define PLL_AO BIT(1) + +struct mtk_pll_data { + int id; + const char *name; + u32 reg; + u32 pwr_reg; + u32 en_mask; + u32 pd_reg; + u32 tuner_reg; + u32 tuner_en_reg; + u8 tuner_en_bit; + int pd_shift; + unsigned int flags; + const struct clk_ops *ops; + u32 rst_bar_mask; + unsigned long fmin; + unsigned long fmax; + int pcwbits; + int pcwibits; + u32 pcw_reg; + int pcw_shift; + u32 pcw_chg_reg; + const struct mtk_pll_div_table *div_table; + const char *parent_name; + u32 en_reg; + u8 pll_en_bit; /* Assume 0, indicates BIT(0) by default */ +}; + +int mtk_clk_register_plls(struct device_node *node, + const struct mtk_pll_data *plls, int num_plls, + struct clk_onecell_data *clk_data); +void mtk_clk_unregister_plls(const struct mtk_pll_data *plls, int num_plls, + struct clk_onecell_data *clk_data); + +#endif /* __DRV_CLK_MTK_PLL_H */ diff --git a/drivers/clk/mediatek/reset.c b/drivers/clk/mediatek/reset.c index ffe464ce7ff8..bcec4b89f449 100644 --- a/drivers/clk/mediatek/reset.c +++ b/drivers/clk/mediatek/reset.c @@ -100,8 +100,7 @@ static void mtk_register_reset_controller_common(struct device_node *np, regmap = device_node_to_regmap(np); if (IS_ERR(regmap)) { - pr_err("Cannot find regmap for %pOF: %ld\n", np, - PTR_ERR(regmap)); + pr_err("Cannot find regmap for %pOF: %pe\n", np, regmap); return; } |