Loading drivers/clk/qcom/clk-alpha-pll.c +235 −0 Original line number Diff line number Diff line Loading @@ -202,6 +202,21 @@ const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = { [PLL_OFF_TEST_CTL_U] = 0x1c, [PLL_OFF_STATUS] = 0x2c, }, [CLK_ALPHA_PLL_TYPE_LUCID_EVO] = { [PLL_OFF_OPMODE] = 0x04, [PLL_OFF_STATUS] = 0x0c, [PLL_OFF_L_VAL] = 0x10, [PLL_OFF_ALPHA_VAL] = 0x14, [PLL_OFF_USER_CTL] = 0x18, [PLL_OFF_USER_CTL_U] = 0x1c, [PLL_OFF_CONFIG_CTL] = 0x20, [PLL_OFF_CONFIG_CTL_U] = 0x24, [PLL_OFF_CONFIG_CTL_U1] = 0x28, [PLL_OFF_TEST_CTL] = 0x2c, [PLL_OFF_TEST_CTL_U] = 0x30, [PLL_OFF_TEST_CTL_U1] = 0x34, }, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_regs); Loading Loading @@ -232,6 +247,8 @@ EXPORT_SYMBOL_GPL(clk_alpha_pll_regs); #define LUCID_5LPE_ENABLE_VOTE_RUN BIT(21) #define LUCID_5LPE_PLL_LATCH_INPUT BIT(14) #define LUCID_5LPE_ALPHA_PLL_ACK_LATCH BIT(13) #define LUCID_EVO_ENABLE_VOTE_RUN BIT(25) #define LUCID_EVO_PLL_L_VAL_MASK GENMASK(15, 0) /* ZONDA PLL specific offsets */ #define ZONDA_PLL_OUT_MASK 0xF Loading Loading @@ -3174,6 +3191,224 @@ const struct clk_ops clk_alpha_pll_postdiv_lucid_5lpe_ops = { }; EXPORT_SYMBOL(clk_alpha_pll_postdiv_lucid_5lpe_ops); static int alpha_pll_lucid_evo_enable(struct clk_hw *hw) { struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); u32 val; int ret; ret = regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &val); if (ret) return ret; /* If in FSM mode, just vote for it */ if (val & LUCID_EVO_ENABLE_VOTE_RUN) { ret = clk_enable_regmap(hw); if (ret) return ret; return wait_for_pll_enable_lock(pll); } /* Check if PLL is already enabled */ ret = lucid_pll_is_enabled(pll, pll->clkr.regmap); if (ret < 0) return ret; else if (ret) { pr_warn("%s PLL is already enabled\n", clk_hw_get_name(&pll->clkr.hw)); return 0; } ret = regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), PLL_RESET_N, PLL_RESET_N); if (ret) return ret; /* Set operation mode to RUN */ regmap_write(pll->clkr.regmap, PLL_OPMODE(pll), PLL_OPMODE_RUN); ret = wait_for_pll_enable_lock(pll); if (ret) return ret; /* Enable the PLL outputs */ ret = regmap_update_bits(pll->clkr.regmap, PLL_USER_CTL(pll), PLL_OUT_MASK, PLL_OUT_MASK); if (ret) return ret; /* Enable the global PLL outputs */ ret = regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), PLL_OUTCTRL, PLL_OUTCTRL); if (ret) return ret; /* Ensure that the write above goes through before returning. */ mb(); return ret; } static void alpha_pll_lucid_evo_disable(struct clk_hw *hw) { struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); u32 val; int ret; ret = regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &val); if (ret) return; /* If in FSM mode, just unvote it */ if (val & LUCID_EVO_ENABLE_VOTE_RUN) { clk_disable_regmap(hw); return; } /* Disable the global PLL output */ ret = regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), PLL_OUTCTRL, 0); if (ret) return; /* Disable the PLL outputs */ ret = regmap_update_bits(pll->clkr.regmap, PLL_USER_CTL(pll), PLL_OUT_MASK, 0); if (ret) return; /* Place the PLL mode in STANDBY */ regmap_write(pll->clkr.regmap, PLL_OPMODE(pll), PLL_OPMODE_STANDBY); } static unsigned long alpha_pll_lucid_evo_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); u32 l, frac; regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l); l &= LUCID_EVO_PLL_L_VAL_MASK; regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL(pll), &frac); return alpha_pll_calc_rate(parent_rate, l, frac, ALPHA_REG_16BIT_WIDTH); } static int clk_lucid_evo_pll_postdiv_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct clk_alpha_pll_postdiv *pll = to_clk_alpha_pll_postdiv(hw); int i, val = 0, div, ret; /* * If the PLL is in FSM mode, then treat set_rate callback as a * no-operation. */ ret = regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &val); if (ret) return ret; if (val & LUCID_EVO_ENABLE_VOTE_RUN) return 0; if (!pll->post_div_table) { pr_err("Missing the post_div_table for the PLL\n"); return -EINVAL; } div = DIV_ROUND_UP_ULL((u64)parent_rate, rate); for (i = 0; i < pll->num_post_div; i++) { if (pll->post_div_table[i].div == div) { val = pll->post_div_table[i].val; break; } } return regmap_update_bits(pll->clkr.regmap, PLL_USER_CTL(pll), (BIT(pll->width) - 1) << pll->post_div_shift, val << pll->post_div_shift); } static void lucid_evo_pll_list_registers(struct seq_file *f, struct clk_hw *hw) { struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); int size, i, val; static struct clk_register_data data[] = { {"PLL_MODE", PLL_OFF_MODE}, {"PLL_OPMODE", PLL_OFF_OPMODE}, {"PLL_STATUS", PLL_OFF_STATUS}, {"PLL_L_VAL", PLL_OFF_L_VAL}, {"PLL_ALPHA_VAL", PLL_OFF_ALPHA_VAL}, {"PLL_USER_CTL", PLL_OFF_USER_CTL}, {"PLL_USER_CTL_U", PLL_OFF_USER_CTL_U}, {"PLL_CONFIG_CTL", PLL_OFF_CONFIG_CTL}, {"PLL_CONFIG_CTL_U", PLL_OFF_CONFIG_CTL_U}, {"PLL_CONFIG_CTL_U1", PLL_OFF_CONFIG_CTL_U1}, {"PLL_TEST_CTL", PLL_OFF_TEST_CTL}, {"PLL_TEST_CTL_U", PLL_OFF_TEST_CTL_U}, {"PLL_TEST_CTL_U1", PLL_OFF_TEST_CTL_U1}, }; static struct clk_register_data data1[] = { {"APSS_PLL_VOTE", 0x0}, }; size = ARRAY_SIZE(data); for (i = 0; i < size; i++) { regmap_read(pll->clkr.regmap, pll->offset + pll->regs[data[i].offset], &val); seq_printf(f, "%20s: 0x%.8x\n", data[i].name, val); } regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &val); if (val & LUCID_EVO_ENABLE_VOTE_RUN) { regmap_read(pll->clkr.regmap, pll->clkr.enable_reg + data1[0].offset, &val); seq_printf(f, "%20s: 0x%.8x\n", data1[0].name, val); } } static struct clk_regmap_ops clk_lucid_evo_pll_regmap_ops = { .list_registers = &lucid_evo_pll_list_registers, }; static void clk_lucid_evo_pll_init(struct clk_hw *hw) { struct clk_regmap *rclk = to_clk_regmap(hw); if (!rclk->ops) rclk->ops = &clk_lucid_evo_pll_regmap_ops; } const struct clk_ops clk_alpha_pll_fixed_lucid_evo_ops = { .prepare = clk_prepare_regmap, .unprepare = clk_unprepare_regmap, .pre_rate_change = clk_pre_change_regmap, .post_rate_change = clk_post_change_regmap, .enable = alpha_pll_lucid_evo_enable, .disable = alpha_pll_lucid_evo_disable, .is_enabled = alpha_pll_lucid_is_enabled, .recalc_rate = alpha_pll_lucid_evo_recalc_rate, .round_rate = clk_alpha_pll_round_rate, .debug_init = clk_common_debug_init, .init = clk_lucid_evo_pll_init, #ifdef CONFIG_COMMON_CLK_QCOM_DEBUG .list_rate_vdd_level = clk_list_rate_vdd_level, #endif }; EXPORT_SYMBOL(clk_alpha_pll_fixed_lucid_evo_ops); const struct clk_ops clk_alpha_pll_postdiv_lucid_evo_ops = { .recalc_rate = clk_alpha_pll_postdiv_fabia_recalc_rate, .round_rate = clk_alpha_pll_postdiv_fabia_round_rate, .set_rate = clk_lucid_evo_pll_postdiv_set_rate, }; EXPORT_SYMBOL(clk_alpha_pll_postdiv_lucid_evo_ops); int clk_regera_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, const struct alpha_pll_config *config) { Loading drivers/clk/qcom/clk-alpha-pll.h +4 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ enum { CLK_ALPHA_PLL_TYPE_ZONDA_5LPE, CLK_ALPHA_PLL_TYPE_REGERA, CLK_ALPHA_PLL_TYPE_AGERA, CLK_ALPHA_PLL_TYPE_LUCID_EVO, CLK_ALPHA_PLL_TYPE_MAX, }; Loading Loading @@ -159,6 +160,9 @@ extern const struct clk_ops clk_trion_pll_ops; extern const struct clk_ops clk_regera_pll_ops; extern const struct clk_ops clk_agera_pll_ops; extern const struct clk_ops clk_alpha_pll_fixed_lucid_evo_ops; extern const struct clk_ops clk_alpha_pll_postdiv_lucid_evo_ops; void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, const struct alpha_pll_config *config); int clk_fabia_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, Loading Loading
drivers/clk/qcom/clk-alpha-pll.c +235 −0 Original line number Diff line number Diff line Loading @@ -202,6 +202,21 @@ const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = { [PLL_OFF_TEST_CTL_U] = 0x1c, [PLL_OFF_STATUS] = 0x2c, }, [CLK_ALPHA_PLL_TYPE_LUCID_EVO] = { [PLL_OFF_OPMODE] = 0x04, [PLL_OFF_STATUS] = 0x0c, [PLL_OFF_L_VAL] = 0x10, [PLL_OFF_ALPHA_VAL] = 0x14, [PLL_OFF_USER_CTL] = 0x18, [PLL_OFF_USER_CTL_U] = 0x1c, [PLL_OFF_CONFIG_CTL] = 0x20, [PLL_OFF_CONFIG_CTL_U] = 0x24, [PLL_OFF_CONFIG_CTL_U1] = 0x28, [PLL_OFF_TEST_CTL] = 0x2c, [PLL_OFF_TEST_CTL_U] = 0x30, [PLL_OFF_TEST_CTL_U1] = 0x34, }, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_regs); Loading Loading @@ -232,6 +247,8 @@ EXPORT_SYMBOL_GPL(clk_alpha_pll_regs); #define LUCID_5LPE_ENABLE_VOTE_RUN BIT(21) #define LUCID_5LPE_PLL_LATCH_INPUT BIT(14) #define LUCID_5LPE_ALPHA_PLL_ACK_LATCH BIT(13) #define LUCID_EVO_ENABLE_VOTE_RUN BIT(25) #define LUCID_EVO_PLL_L_VAL_MASK GENMASK(15, 0) /* ZONDA PLL specific offsets */ #define ZONDA_PLL_OUT_MASK 0xF Loading Loading @@ -3174,6 +3191,224 @@ const struct clk_ops clk_alpha_pll_postdiv_lucid_5lpe_ops = { }; EXPORT_SYMBOL(clk_alpha_pll_postdiv_lucid_5lpe_ops); static int alpha_pll_lucid_evo_enable(struct clk_hw *hw) { struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); u32 val; int ret; ret = regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &val); if (ret) return ret; /* If in FSM mode, just vote for it */ if (val & LUCID_EVO_ENABLE_VOTE_RUN) { ret = clk_enable_regmap(hw); if (ret) return ret; return wait_for_pll_enable_lock(pll); } /* Check if PLL is already enabled */ ret = lucid_pll_is_enabled(pll, pll->clkr.regmap); if (ret < 0) return ret; else if (ret) { pr_warn("%s PLL is already enabled\n", clk_hw_get_name(&pll->clkr.hw)); return 0; } ret = regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), PLL_RESET_N, PLL_RESET_N); if (ret) return ret; /* Set operation mode to RUN */ regmap_write(pll->clkr.regmap, PLL_OPMODE(pll), PLL_OPMODE_RUN); ret = wait_for_pll_enable_lock(pll); if (ret) return ret; /* Enable the PLL outputs */ ret = regmap_update_bits(pll->clkr.regmap, PLL_USER_CTL(pll), PLL_OUT_MASK, PLL_OUT_MASK); if (ret) return ret; /* Enable the global PLL outputs */ ret = regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), PLL_OUTCTRL, PLL_OUTCTRL); if (ret) return ret; /* Ensure that the write above goes through before returning. */ mb(); return ret; } static void alpha_pll_lucid_evo_disable(struct clk_hw *hw) { struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); u32 val; int ret; ret = regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &val); if (ret) return; /* If in FSM mode, just unvote it */ if (val & LUCID_EVO_ENABLE_VOTE_RUN) { clk_disable_regmap(hw); return; } /* Disable the global PLL output */ ret = regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), PLL_OUTCTRL, 0); if (ret) return; /* Disable the PLL outputs */ ret = regmap_update_bits(pll->clkr.regmap, PLL_USER_CTL(pll), PLL_OUT_MASK, 0); if (ret) return; /* Place the PLL mode in STANDBY */ regmap_write(pll->clkr.regmap, PLL_OPMODE(pll), PLL_OPMODE_STANDBY); } static unsigned long alpha_pll_lucid_evo_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); u32 l, frac; regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l); l &= LUCID_EVO_PLL_L_VAL_MASK; regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL(pll), &frac); return alpha_pll_calc_rate(parent_rate, l, frac, ALPHA_REG_16BIT_WIDTH); } static int clk_lucid_evo_pll_postdiv_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct clk_alpha_pll_postdiv *pll = to_clk_alpha_pll_postdiv(hw); int i, val = 0, div, ret; /* * If the PLL is in FSM mode, then treat set_rate callback as a * no-operation. */ ret = regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &val); if (ret) return ret; if (val & LUCID_EVO_ENABLE_VOTE_RUN) return 0; if (!pll->post_div_table) { pr_err("Missing the post_div_table for the PLL\n"); return -EINVAL; } div = DIV_ROUND_UP_ULL((u64)parent_rate, rate); for (i = 0; i < pll->num_post_div; i++) { if (pll->post_div_table[i].div == div) { val = pll->post_div_table[i].val; break; } } return regmap_update_bits(pll->clkr.regmap, PLL_USER_CTL(pll), (BIT(pll->width) - 1) << pll->post_div_shift, val << pll->post_div_shift); } static void lucid_evo_pll_list_registers(struct seq_file *f, struct clk_hw *hw) { struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); int size, i, val; static struct clk_register_data data[] = { {"PLL_MODE", PLL_OFF_MODE}, {"PLL_OPMODE", PLL_OFF_OPMODE}, {"PLL_STATUS", PLL_OFF_STATUS}, {"PLL_L_VAL", PLL_OFF_L_VAL}, {"PLL_ALPHA_VAL", PLL_OFF_ALPHA_VAL}, {"PLL_USER_CTL", PLL_OFF_USER_CTL}, {"PLL_USER_CTL_U", PLL_OFF_USER_CTL_U}, {"PLL_CONFIG_CTL", PLL_OFF_CONFIG_CTL}, {"PLL_CONFIG_CTL_U", PLL_OFF_CONFIG_CTL_U}, {"PLL_CONFIG_CTL_U1", PLL_OFF_CONFIG_CTL_U1}, {"PLL_TEST_CTL", PLL_OFF_TEST_CTL}, {"PLL_TEST_CTL_U", PLL_OFF_TEST_CTL_U}, {"PLL_TEST_CTL_U1", PLL_OFF_TEST_CTL_U1}, }; static struct clk_register_data data1[] = { {"APSS_PLL_VOTE", 0x0}, }; size = ARRAY_SIZE(data); for (i = 0; i < size; i++) { regmap_read(pll->clkr.regmap, pll->offset + pll->regs[data[i].offset], &val); seq_printf(f, "%20s: 0x%.8x\n", data[i].name, val); } regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &val); if (val & LUCID_EVO_ENABLE_VOTE_RUN) { regmap_read(pll->clkr.regmap, pll->clkr.enable_reg + data1[0].offset, &val); seq_printf(f, "%20s: 0x%.8x\n", data1[0].name, val); } } static struct clk_regmap_ops clk_lucid_evo_pll_regmap_ops = { .list_registers = &lucid_evo_pll_list_registers, }; static void clk_lucid_evo_pll_init(struct clk_hw *hw) { struct clk_regmap *rclk = to_clk_regmap(hw); if (!rclk->ops) rclk->ops = &clk_lucid_evo_pll_regmap_ops; } const struct clk_ops clk_alpha_pll_fixed_lucid_evo_ops = { .prepare = clk_prepare_regmap, .unprepare = clk_unprepare_regmap, .pre_rate_change = clk_pre_change_regmap, .post_rate_change = clk_post_change_regmap, .enable = alpha_pll_lucid_evo_enable, .disable = alpha_pll_lucid_evo_disable, .is_enabled = alpha_pll_lucid_is_enabled, .recalc_rate = alpha_pll_lucid_evo_recalc_rate, .round_rate = clk_alpha_pll_round_rate, .debug_init = clk_common_debug_init, .init = clk_lucid_evo_pll_init, #ifdef CONFIG_COMMON_CLK_QCOM_DEBUG .list_rate_vdd_level = clk_list_rate_vdd_level, #endif }; EXPORT_SYMBOL(clk_alpha_pll_fixed_lucid_evo_ops); const struct clk_ops clk_alpha_pll_postdiv_lucid_evo_ops = { .recalc_rate = clk_alpha_pll_postdiv_fabia_recalc_rate, .round_rate = clk_alpha_pll_postdiv_fabia_round_rate, .set_rate = clk_lucid_evo_pll_postdiv_set_rate, }; EXPORT_SYMBOL(clk_alpha_pll_postdiv_lucid_evo_ops); int clk_regera_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, const struct alpha_pll_config *config) { Loading
drivers/clk/qcom/clk-alpha-pll.h +4 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ enum { CLK_ALPHA_PLL_TYPE_ZONDA_5LPE, CLK_ALPHA_PLL_TYPE_REGERA, CLK_ALPHA_PLL_TYPE_AGERA, CLK_ALPHA_PLL_TYPE_LUCID_EVO, CLK_ALPHA_PLL_TYPE_MAX, }; Loading Loading @@ -159,6 +160,9 @@ extern const struct clk_ops clk_trion_pll_ops; extern const struct clk_ops clk_regera_pll_ops; extern const struct clk_ops clk_agera_pll_ops; extern const struct clk_ops clk_alpha_pll_fixed_lucid_evo_ops; extern const struct clk_ops clk_alpha_pll_postdiv_lucid_evo_ops; void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, const struct alpha_pll_config *config); int clk_fabia_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, Loading