Skip to content

Commit

Permalink
clk: qcom: clk-alpha-pll: Add support for Lucid 5LPE PLL
Browse files Browse the repository at this point in the history
Lucid 5LPE is a slightly different Lucid PLL with different offsets and
porgramming sequence so add support for these

Signed-off-by: Vivek Aknurwar <viveka@codeaurora.org>
Signed-off-by: Jeevan Shriram <jshriram@codeaurora.org>
[vkoul: rebase and tidy up for upstream]
Signed-off-by: Vinod Koul <vkoul@kernel.org>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Link: https://lore.kernel.org/r/20210127070811.152690-4-vkoul@kernel.org
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
  • Loading branch information
Vivek Aknurwar authored and Stephen Boyd committed Feb 8, 2021
1 parent 80ca776 commit f4c7e27
Show file tree
Hide file tree
Showing 2 changed files with 177 additions and 0 deletions.
173 changes: 173 additions & 0 deletions drivers/clk/qcom/clk-alpha-pll.c
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,12 @@ EXPORT_SYMBOL_GPL(clk_alpha_pll_regs);
/* LUCID PLL specific settings and offsets */
#define LUCID_PCAL_DONE BIT(27)

/* LUCID 5LPE PLL specific settings and offsets */
#define LUCID_5LPE_PCAL_DONE BIT(11)
#define LUCID_5LPE_ALPHA_PLL_ACK_LATCH BIT(13)
#define LUCID_5LPE_PLL_LATCH_INPUT BIT(14)
#define LUCID_5LPE_ENABLE_VOTE_RUN BIT(21)

#define pll_alpha_width(p) \
((PLL_ALPHA_VAL_U(p) - PLL_ALPHA_VAL(p) == 4) ? \
ALPHA_REG_BITWIDTH : ALPHA_REG_16BIT_WIDTH)
Expand Down Expand Up @@ -1604,3 +1610,170 @@ const struct clk_ops clk_alpha_pll_agera_ops = {
.set_rate = clk_alpha_pll_agera_set_rate,
};
EXPORT_SYMBOL_GPL(clk_alpha_pll_agera_ops);

static int alpha_pll_lucid_5lpe_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_5LPE_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, return if enabled */
ret = trion_pll_is_enabled(pll, pll->clkr.regmap);
if (ret < 0)
return ret;

ret = regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), PLL_RESET_N, PLL_RESET_N);
if (ret)
return ret;

regmap_write(pll->clkr.regmap, PLL_OPMODE(pll), PLL_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 */
return regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), PLL_OUTCTRL, PLL_OUTCTRL);
}

static void alpha_pll_lucid_5lpe_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_5LPE_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_STANDBY);
}

/*
* The Lucid 5LPE PLL requires a power-on self-calibration which happens
* when the PLL comes out of reset. Calibrate in case it is not completed.
*/
static int alpha_pll_lucid_5lpe_prepare(struct clk_hw *hw)
{
struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
struct clk_hw *p;
u32 val = 0;
int ret;

/* Return early if calibration is not needed. */
regmap_read(pll->clkr.regmap, PLL_MODE(pll), &val);
if (val & LUCID_5LPE_PCAL_DONE)
return 0;

p = clk_hw_get_parent(hw);
if (!p)
return -EINVAL;

ret = alpha_pll_lucid_5lpe_enable(hw);
if (ret)
return ret;

alpha_pll_lucid_5lpe_disable(hw);

return 0;
}

static int alpha_pll_lucid_5lpe_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long prate)
{
return __alpha_pll_trion_set_rate(hw, rate, prate,
LUCID_5LPE_PLL_LATCH_INPUT,
LUCID_5LPE_ALPHA_PLL_ACK_LATCH);
}

static int clk_lucid_5lpe_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;
u32 mask;

/*
* 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_5LPE_ENABLE_VOTE_RUN)
return 0;

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;
}
}

mask = GENMASK(pll->width + pll->post_div_shift - 1, pll->post_div_shift);
return regmap_update_bits(pll->clkr.regmap, PLL_USER_CTL(pll),
mask, val << pll->post_div_shift);
}

const struct clk_ops clk_alpha_pll_lucid_5lpe_ops = {
.prepare = alpha_pll_lucid_5lpe_prepare,
.enable = alpha_pll_lucid_5lpe_enable,
.disable = alpha_pll_lucid_5lpe_disable,
.is_enabled = clk_trion_pll_is_enabled,
.recalc_rate = clk_trion_pll_recalc_rate,
.round_rate = clk_alpha_pll_round_rate,
.set_rate = alpha_pll_lucid_5lpe_set_rate,
};
EXPORT_SYMBOL(clk_alpha_pll_lucid_5lpe_ops);

const struct clk_ops clk_alpha_pll_fixed_lucid_5lpe_ops = {
.enable = alpha_pll_lucid_5lpe_enable,
.disable = alpha_pll_lucid_5lpe_disable,
.is_enabled = clk_trion_pll_is_enabled,
.recalc_rate = clk_trion_pll_recalc_rate,
.round_rate = clk_alpha_pll_round_rate,
};
EXPORT_SYMBOL(clk_alpha_pll_fixed_lucid_5lpe_ops);

const struct clk_ops clk_alpha_pll_postdiv_lucid_5lpe_ops = {
.recalc_rate = clk_alpha_pll_postdiv_fabia_recalc_rate,
.round_rate = clk_alpha_pll_postdiv_fabia_round_rate,
.set_rate = clk_lucid_5lpe_pll_postdiv_set_rate,
};
EXPORT_SYMBOL(clk_alpha_pll_postdiv_lucid_5lpe_ops);
4 changes: 4 additions & 0 deletions drivers/clk/qcom/clk-alpha-pll.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,10 @@ extern const struct clk_ops clk_alpha_pll_lucid_ops;
extern const struct clk_ops clk_alpha_pll_postdiv_lucid_ops;
extern const struct clk_ops clk_alpha_pll_agera_ops;

extern const struct clk_ops clk_alpha_pll_lucid_5lpe_ops;
extern const struct clk_ops clk_alpha_pll_fixed_lucid_5lpe_ops;
extern const struct clk_ops clk_alpha_pll_postdiv_lucid_5lpe_ops;

void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
const struct alpha_pll_config *config);
void clk_fabia_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
Expand Down

0 comments on commit f4c7e27

Please sign in to comment.