Loading drivers/clk/qcom/clk-branch.c +54 −2 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2013, The Linux Foundation. All rights reserved. * Copyright (c) 2013, 2016, The Linux Foundation. All rights reserved. */ #include <linux/kernel.h> Loading @@ -8,6 +8,7 @@ #include <linux/err.h> #include <linux/delay.h> #include <linux/export.h> #include <linux/clk.h> #include <linux/clk-provider.h> #include <linux/regmap.h> Loading Loading @@ -152,6 +153,57 @@ const struct clk_ops clk_branch2_aon_ops = { }; EXPORT_SYMBOL_GPL(clk_branch2_aon_ops); static unsigned long clk_branch2_hw_ctl_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { return parent_rate; } static int clk_branch2_hw_ctl_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) { struct clk_hw *clkp; clkp = clk_hw_get_parent(hw); if (!clkp) return -EINVAL; req->best_parent_hw = clkp; req->best_parent_rate = clk_round_rate(clkp->clk, req->rate); return 0; } static int clk_branch2_hw_ctl_enable(struct clk_hw *hw) { struct clk_hw *parent = clk_hw_get_parent(hw); /* The parent branch clock should have been prepared prior to this. */ if (!parent || (parent && !clk_hw_is_prepared(parent))) return -EINVAL; return clk_enable_regmap(hw); } static void clk_branch2_hw_ctl_disable(struct clk_hw *hw) { struct clk_hw *parent = clk_hw_get_parent(hw); if (!parent) return; clk_disable_regmap(hw); } const struct clk_ops clk_branch2_hw_ctl_ops = { .enable = clk_branch2_hw_ctl_enable, .disable = clk_branch2_hw_ctl_disable, .is_enabled = clk_is_enabled_regmap, .recalc_rate = clk_branch2_hw_ctl_recalc_rate, .determine_rate = clk_branch2_hw_ctl_determine_rate, }; EXPORT_SYMBOL(clk_branch2_hw_ctl_ops); const struct clk_ops clk_branch_simple_ops = { .enable = clk_enable_regmap, .disable = clk_disable_regmap, Loading drivers/clk/qcom/clk-branch.h +3 −2 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0 */ /* Copyright (c) 2013, The Linux Foundation. All rights reserved. */ /* SPDX-License-Identifier: GPL-2.0-only */ /* Copyright (c) 2013, 2016, The Linux Foundation. All rights reserved. */ #ifndef __QCOM_CLK_BRANCH_H__ #define __QCOM_CLK_BRANCH_H__ Loading Loading @@ -39,6 +39,7 @@ struct clk_branch { extern const struct clk_ops clk_branch_ops; extern const struct clk_ops clk_branch2_ops; extern const struct clk_ops clk_branch2_hw_ctl_ops; extern const struct clk_ops clk_branch_simple_ops; extern const struct clk_ops clk_branch2_aon_ops; Loading drivers/clk/qcom/clk-rcg2.c +46 −16 Original line number Diff line number Diff line Loading @@ -175,6 +175,16 @@ static int clk_rcg2_clear_force_enable(struct clk_hw *hw) CMD_ROOT_EN, 0); } static bool clk_rcg2_is_force_enabled(struct clk_hw *hw) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); u32 val = 0; regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG, &val); return val & CMD_ROOT_EN; } static int prepare_enable_rcg_srcs(struct clk *curr, struct clk *new) { int rc = 0; Loading Loading @@ -247,6 +257,7 @@ clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) struct clk_rcg2 *rcg = to_clk_rcg2(hw); const struct freq_tbl *f_curr; u32 cfg, src, hid_div, m = 0, n = 0, mode = 0, mask; unsigned long rrate = 0; regmap_read(rcg->clkr.regmap, RCG_CFG_OFFSET(rcg), &cfg); src = cfg; Loading Loading @@ -284,7 +295,16 @@ clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) hid_div &= mask; } return calc_rate(parent_rate, m, n, mode, hid_div); rrate = calc_rate(parent_rate, m, n, mode, hid_div); /* * Check to cover the case when the RCG has been initialized to a * non-CXO frequency before the clock driver has taken control of it. */ if (rcg->enable_safe_config && !rcg->current_freq) rcg->current_freq = rrate; return rrate; } static int _freq_tbl_determine_rate(struct clk_hw *hw, const struct freq_tbl *f, Loading Loading @@ -431,6 +451,7 @@ static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate, const struct freq_tbl *f, *f_curr; int ret, curr_src_index, new_src_index; struct clk_hw *curr_src = NULL, *new_src = NULL; bool force_enabled = false; switch (policy) { case FLOOR: Loading Loading @@ -482,6 +503,10 @@ static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate, /* The RCG could currently be disabled. Enable its parents. */ ret = prepare_enable_rcg_srcs(curr_src->clk, new_src->clk); if (ret) return ret; force_enabled = clk_rcg2_is_force_enabled(hw); if (!force_enabled) clk_rcg2_set_force_enable(hw); } Loading @@ -490,6 +515,7 @@ static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate, return ret; if (rcg->flags & FORCE_ENABLE_RCG) { if (!force_enabled) clk_rcg2_clear_force_enable(hw); disable_unprepare_rcg_srcs(curr_src->clk, new_src->clk); } Loading Loading @@ -528,11 +554,10 @@ static int clk_rcg2_enable(struct clk_hw *hw) struct clk_rcg2 *rcg = to_clk_rcg2(hw); unsigned long rate; const struct freq_tbl *f; int ret; if (rcg->flags & FORCE_ENABLE_RCG) { if (rcg->flags & FORCE_ENABLE_RCG) clk_rcg2_set_force_enable(hw); return 0; } if (!rcg->enable_safe_config) return 0; Loading @@ -559,24 +584,27 @@ static int clk_rcg2_enable(struct clk_hw *hw) if (rate == cxo_f.freq) f = &cxo_f; if (!(rcg->flags & FORCE_ENABLE_RCG)) clk_rcg2_set_force_enable(hw); clk_rcg2_configure(rcg, f); ret = clk_rcg2_configure(rcg, f); if (!(rcg->flags & FORCE_ENABLE_RCG)) clk_rcg2_clear_force_enable(hw); return 0; return ret; } static void clk_rcg2_disable(struct clk_hw *hw) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); int ret; if (rcg->flags & FORCE_ENABLE_RCG) { if (!rcg->enable_safe_config) { if (rcg->flags & FORCE_ENABLE_RCG) clk_rcg2_clear_force_enable(hw); return; } if (!rcg->enable_safe_config) return; /* * Park the RCG at a safe configuration - sourced off the CXO. This is * needed for 2 reasons: In the case of RCGs sourcing PSCBCs, due to a Loading @@ -594,7 +622,9 @@ static void clk_rcg2_disable(struct clk_hw *hw) * online. Therefore, the RCG can safely be switched. */ clk_rcg2_set_force_enable(hw); clk_rcg2_configure(rcg, &cxo_f); ret = clk_rcg2_configure(rcg, &cxo_f); if (ret) pr_err("%s: CXO configuration failed\n", clk_hw_get_name(hw)); clk_rcg2_clear_force_enable(hw); } Loading Loading
drivers/clk/qcom/clk-branch.c +54 −2 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2013, The Linux Foundation. All rights reserved. * Copyright (c) 2013, 2016, The Linux Foundation. All rights reserved. */ #include <linux/kernel.h> Loading @@ -8,6 +8,7 @@ #include <linux/err.h> #include <linux/delay.h> #include <linux/export.h> #include <linux/clk.h> #include <linux/clk-provider.h> #include <linux/regmap.h> Loading Loading @@ -152,6 +153,57 @@ const struct clk_ops clk_branch2_aon_ops = { }; EXPORT_SYMBOL_GPL(clk_branch2_aon_ops); static unsigned long clk_branch2_hw_ctl_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { return parent_rate; } static int clk_branch2_hw_ctl_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) { struct clk_hw *clkp; clkp = clk_hw_get_parent(hw); if (!clkp) return -EINVAL; req->best_parent_hw = clkp; req->best_parent_rate = clk_round_rate(clkp->clk, req->rate); return 0; } static int clk_branch2_hw_ctl_enable(struct clk_hw *hw) { struct clk_hw *parent = clk_hw_get_parent(hw); /* The parent branch clock should have been prepared prior to this. */ if (!parent || (parent && !clk_hw_is_prepared(parent))) return -EINVAL; return clk_enable_regmap(hw); } static void clk_branch2_hw_ctl_disable(struct clk_hw *hw) { struct clk_hw *parent = clk_hw_get_parent(hw); if (!parent) return; clk_disable_regmap(hw); } const struct clk_ops clk_branch2_hw_ctl_ops = { .enable = clk_branch2_hw_ctl_enable, .disable = clk_branch2_hw_ctl_disable, .is_enabled = clk_is_enabled_regmap, .recalc_rate = clk_branch2_hw_ctl_recalc_rate, .determine_rate = clk_branch2_hw_ctl_determine_rate, }; EXPORT_SYMBOL(clk_branch2_hw_ctl_ops); const struct clk_ops clk_branch_simple_ops = { .enable = clk_enable_regmap, .disable = clk_disable_regmap, Loading
drivers/clk/qcom/clk-branch.h +3 −2 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0 */ /* Copyright (c) 2013, The Linux Foundation. All rights reserved. */ /* SPDX-License-Identifier: GPL-2.0-only */ /* Copyright (c) 2013, 2016, The Linux Foundation. All rights reserved. */ #ifndef __QCOM_CLK_BRANCH_H__ #define __QCOM_CLK_BRANCH_H__ Loading Loading @@ -39,6 +39,7 @@ struct clk_branch { extern const struct clk_ops clk_branch_ops; extern const struct clk_ops clk_branch2_ops; extern const struct clk_ops clk_branch2_hw_ctl_ops; extern const struct clk_ops clk_branch_simple_ops; extern const struct clk_ops clk_branch2_aon_ops; Loading
drivers/clk/qcom/clk-rcg2.c +46 −16 Original line number Diff line number Diff line Loading @@ -175,6 +175,16 @@ static int clk_rcg2_clear_force_enable(struct clk_hw *hw) CMD_ROOT_EN, 0); } static bool clk_rcg2_is_force_enabled(struct clk_hw *hw) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); u32 val = 0; regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG, &val); return val & CMD_ROOT_EN; } static int prepare_enable_rcg_srcs(struct clk *curr, struct clk *new) { int rc = 0; Loading Loading @@ -247,6 +257,7 @@ clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) struct clk_rcg2 *rcg = to_clk_rcg2(hw); const struct freq_tbl *f_curr; u32 cfg, src, hid_div, m = 0, n = 0, mode = 0, mask; unsigned long rrate = 0; regmap_read(rcg->clkr.regmap, RCG_CFG_OFFSET(rcg), &cfg); src = cfg; Loading Loading @@ -284,7 +295,16 @@ clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) hid_div &= mask; } return calc_rate(parent_rate, m, n, mode, hid_div); rrate = calc_rate(parent_rate, m, n, mode, hid_div); /* * Check to cover the case when the RCG has been initialized to a * non-CXO frequency before the clock driver has taken control of it. */ if (rcg->enable_safe_config && !rcg->current_freq) rcg->current_freq = rrate; return rrate; } static int _freq_tbl_determine_rate(struct clk_hw *hw, const struct freq_tbl *f, Loading Loading @@ -431,6 +451,7 @@ static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate, const struct freq_tbl *f, *f_curr; int ret, curr_src_index, new_src_index; struct clk_hw *curr_src = NULL, *new_src = NULL; bool force_enabled = false; switch (policy) { case FLOOR: Loading Loading @@ -482,6 +503,10 @@ static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate, /* The RCG could currently be disabled. Enable its parents. */ ret = prepare_enable_rcg_srcs(curr_src->clk, new_src->clk); if (ret) return ret; force_enabled = clk_rcg2_is_force_enabled(hw); if (!force_enabled) clk_rcg2_set_force_enable(hw); } Loading @@ -490,6 +515,7 @@ static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate, return ret; if (rcg->flags & FORCE_ENABLE_RCG) { if (!force_enabled) clk_rcg2_clear_force_enable(hw); disable_unprepare_rcg_srcs(curr_src->clk, new_src->clk); } Loading Loading @@ -528,11 +554,10 @@ static int clk_rcg2_enable(struct clk_hw *hw) struct clk_rcg2 *rcg = to_clk_rcg2(hw); unsigned long rate; const struct freq_tbl *f; int ret; if (rcg->flags & FORCE_ENABLE_RCG) { if (rcg->flags & FORCE_ENABLE_RCG) clk_rcg2_set_force_enable(hw); return 0; } if (!rcg->enable_safe_config) return 0; Loading @@ -559,24 +584,27 @@ static int clk_rcg2_enable(struct clk_hw *hw) if (rate == cxo_f.freq) f = &cxo_f; if (!(rcg->flags & FORCE_ENABLE_RCG)) clk_rcg2_set_force_enable(hw); clk_rcg2_configure(rcg, f); ret = clk_rcg2_configure(rcg, f); if (!(rcg->flags & FORCE_ENABLE_RCG)) clk_rcg2_clear_force_enable(hw); return 0; return ret; } static void clk_rcg2_disable(struct clk_hw *hw) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); int ret; if (rcg->flags & FORCE_ENABLE_RCG) { if (!rcg->enable_safe_config) { if (rcg->flags & FORCE_ENABLE_RCG) clk_rcg2_clear_force_enable(hw); return; } if (!rcg->enable_safe_config) return; /* * Park the RCG at a safe configuration - sourced off the CXO. This is * needed for 2 reasons: In the case of RCGs sourcing PSCBCs, due to a Loading @@ -594,7 +622,9 @@ static void clk_rcg2_disable(struct clk_hw *hw) * online. Therefore, the RCG can safely be switched. */ clk_rcg2_set_force_enable(hw); clk_rcg2_configure(rcg, &cxo_f); ret = clk_rcg2_configure(rcg, &cxo_f); if (ret) pr_err("%s: CXO configuration failed\n", clk_hw_get_name(hw)); clk_rcg2_clear_force_enable(hw); } Loading