diff --git a/drivers/clk/qcom/clk-pll.c b/drivers/clk/qcom/clk-pll.c index 26ba709f43c8..e6b45758090d 100644 --- a/drivers/clk/qcom/clk-pll.c +++ b/drivers/clk/qcom/clk-pll.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2013, 2021, The Linux Foundation. All rights reserved. */ #include @@ -14,6 +14,7 @@ #include +#include "clk-debug.h" #include "clk-pll.h" #include "common.h" @@ -130,7 +131,8 @@ clk_pll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) f = find_freq(pll->freq_tbl, req->rate); if (!f) - req->rate = clk_pll_recalc_rate(hw, req->best_parent_rate); + req->rate = DIV_ROUND_UP_ULL(req->rate, req->best_parent_rate) + * req->best_parent_rate; else req->rate = f->freq; @@ -334,3 +336,76 @@ const struct clk_ops clk_pll_sr2_ops = { .determine_rate = clk_pll_determine_rate, }; EXPORT_SYMBOL_GPL(clk_pll_sr2_ops); + +static int +clk_pll_hf_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long prate) +{ + struct clk_pll *pll = to_clk_pll(hw); + bool enabled; + u32 mode, l_val; + u32 enable_mask = PLL_OUTCTRL | PLL_BYPASSNL | PLL_RESET_N; + + l_val = rate / prate; + + regmap_read(pll->clkr.regmap, pll->mode_reg, &mode); + enabled = (mode & enable_mask) == enable_mask; + + if (enabled) + clk_pll_disable(hw); + + regmap_update_bits(pll->clkr.regmap, pll->l_reg, 0x3ff, l_val); + regmap_update_bits(pll->clkr.regmap, pll->m_reg, 0x7ffff, 0); + regmap_update_bits(pll->clkr.regmap, pll->n_reg, 0x7ffff, 1); + + if (enabled) + clk_pll_sr2_enable(hw); + + return 0; +} + +static void clk_pll_hf_list_registers(struct seq_file *f, struct clk_hw *hw) +{ + struct clk_pll *pll = to_clk_pll(hw); + int size, i, val; + + static struct clk_register_data data[] = { + {"PLL_MODE", 0x0}, + {"PLL_L_VAL", 0x4}, + {"PLL_M_VAL", 0x8}, + {"PLL_N_VAL", 0xC}, + {"PLL_USER_CTL", 0x10}, + {"PLL_CONFIG_CTL", 0x14}, + {"PLL_STATUS_CTL", 0x1C}, + }; + + size = ARRAY_SIZE(data); + + for (i = 0; i < size; i++) { + regmap_read(pll->clkr.regmap, pll->mode_reg + data[i].offset, + &val); + clock_debug_output(f, "%20s: 0x%.8x\n", data[i].name, val); + } +} + +static struct clk_regmap_ops clk_pll_hf_regmap_ops = { + .list_registers = &clk_pll_hf_list_registers, +}; + +static void clk_pll_hf_init(struct clk_hw *hw) +{ + struct clk_regmap *rclk = to_clk_regmap(hw); + + if (!rclk->ops) + rclk->ops = &clk_pll_hf_regmap_ops; +} + +const struct clk_ops clk_pll_hf_ops = { + .enable = clk_pll_sr2_enable, + .disable = clk_pll_disable, + .set_rate = clk_pll_hf_set_rate, + .recalc_rate = clk_pll_recalc_rate, + .determine_rate = clk_pll_determine_rate, + .debug_init = clk_common_debug_init, + .init = clk_pll_hf_init, +}; +EXPORT_SYMBOL(clk_pll_hf_ops); diff --git a/drivers/clk/qcom/clk-pll.h b/drivers/clk/qcom/clk-pll.h index 532f5a9d2888..d9a11facebff 100644 --- a/drivers/clk/qcom/clk-pll.h +++ b/drivers/clk/qcom/clk-pll.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2013, 2021, The Linux Foundation. All rights reserved. */ #ifndef __QCOM_CLK_PLL_H__ @@ -55,6 +55,7 @@ struct clk_pll { extern const struct clk_ops clk_pll_ops; extern const struct clk_ops clk_pll_vote_ops; extern const struct clk_ops clk_pll_sr2_ops; +extern const struct clk_ops clk_pll_hf_ops; #define to_clk_pll(_hw) container_of(to_clk_regmap(_hw), struct clk_pll, clkr) diff --git a/include/dt-bindings/clock/qcom,cmn-blk-pll.h b/include/dt-bindings/clock/qcom,cmn-blk-pll.h new file mode 100644 index 000000000000..ea70bd0a5bd4 --- /dev/null +++ b/include/dt-bindings/clock/qcom,cmn-blk-pll.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, 2021, The Linux Foundation. All rights reserved. + */ + +#ifndef _DT_BINDINGS_CLK_QCOM_CMN_BLK_PLL_H +#define _DT_BINDINGS_CLK_QCOM_CMN_BLK_PLL_H + +#define CMN_BLK_PLL 0 + +#endif