diff options
Diffstat (limited to 'drivers/clk/mediatek/clk-mt8195-topckgen.c')
-rw-r--r-- | drivers/clk/mediatek/clk-mt8195-topckgen.c | 109 |
1 files changed, 88 insertions, 21 deletions
diff --git a/drivers/clk/mediatek/clk-mt8195-topckgen.c b/drivers/clk/mediatek/clk-mt8195-topckgen.c index 3e2aba9c40bb..1e016329c1d2 100644 --- a/drivers/clk/mediatek/clk-mt8195-topckgen.c +++ b/drivers/clk/mediatek/clk-mt8195-topckgen.c @@ -298,11 +298,14 @@ static const char * const ipu_if_parents[] = { "mmpll_d4" }; +/* + * MFG can be also parented to "univpll_d6" and "univpll_d7": + * these have been removed from the parents list to let us + * achieve GPU DVFS without any special clock handlers. + */ static const char * const mfg_parents[] = { "clk26m", - "mainpll_d5_d2", - "univpll_d6", - "univpll_d7" + "mainpll_d5_d2" }; static const char * const camtg_parents[] = { @@ -1149,11 +1152,6 @@ static const struct mtk_mux top_mtk_muxes[] = { */ }; -static struct mtk_composite top_muxes[] = { - /* CLK_MISC_CFG_3 */ - MUX(CLK_TOP_MFG_CK_FAST_REF, "mfg_ck_fast_ref", mfg_fast_parents, 0x0250, 8, 1), -}; - static const struct mtk_composite top_adj_divs[] = { DIV_GATE(CLK_TOP_APLL12_DIV0, "apll12_div0", "top_i2si1_mck", 0x0320, 0, 0x0328, 8, 0), DIV_GATE(CLK_TOP_APLL12_DIV1, "apll12_div1", "top_i2si2_mck", 0x0320, 1, 0x0328, 8, 8), @@ -1222,10 +1220,26 @@ static const struct of_device_id of_match_clk_mt8195_topck[] = { {} }; +/* Register mux notifier for MFG mux */ +static int clk_mt8195_reg_mfg_mux_notifier(struct device *dev, struct clk *clk) +{ + struct mtk_mux_nb *mfg_mux_nb; + + mfg_mux_nb = devm_kzalloc(dev, sizeof(*mfg_mux_nb), GFP_KERNEL); + if (!mfg_mux_nb) + return -ENOMEM; + + mfg_mux_nb->ops = &clk_mux_ops; + mfg_mux_nb->bypass_index = 0; /* Bypass to TOP_MFG_CORE_TMP */ + + return devm_mtk_clk_mux_notifier_register(dev, clk, mfg_mux_nb); +} + static int clk_mt8195_topck_probe(struct platform_device *pdev) { - struct clk_onecell_data *top_clk_data; + struct clk_hw_onecell_data *top_clk_data; struct device_node *node = pdev->dev.of_node; + struct clk_hw *hw; int r; void __iomem *base; @@ -1239,32 +1253,85 @@ 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 = of_clk_add_provider(node, of_clk_src_onecell_get, top_clk_data); + r = mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), top_clk_data); if (r) - goto free_top_data; + 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; + + hw = devm_clk_hw_register_mux(&pdev->dev, "mfg_ck_fast_ref", mfg_fast_parents, + ARRAY_SIZE(mfg_fast_parents), CLK_SET_RATE_PARENT, + (base + 0x250), 8, 1, 0, &mt8195_clk_lock); + if (IS_ERR(hw)) { + r = PTR_ERR(hw); + goto unregister_muxes; + } + top_clk_data->hws[CLK_TOP_MFG_CK_FAST_REF] = hw; + + r = clk_mt8195_reg_mfg_mux_notifier(&pdev->dev, + top_clk_data->hws[CLK_TOP_MFG_CK_FAST_REF]->clk); + 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_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_hw_provider(node, of_clk_hw_onecell_get, top_clk_data); + if (r) + 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_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_hw_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_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, |