|
@@ -185,12 +185,45 @@ static void meson_clk_pll_init(struct clk_hw *hw)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static int meson_clk_pll_enable(struct clk_hw *hw)
|
|
|
+{
|
|
|
+ struct clk_regmap *clk = to_clk_regmap(hw);
|
|
|
+ struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
|
|
|
+
|
|
|
+ /* Make sure the pll is in reset */
|
|
|
+ meson_parm_write(clk->map, &pll->rst, 1);
|
|
|
+
|
|
|
+ /* Enable the pll */
|
|
|
+ meson_parm_write(clk->map, &pll->en, 1);
|
|
|
+
|
|
|
+ /* Take the pll out reset */
|
|
|
+ meson_parm_write(clk->map, &pll->rst, 0);
|
|
|
+
|
|
|
+ if (meson_clk_pll_wait_lock(hw))
|
|
|
+ return -EIO;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void meson_clk_pll_disable(struct clk_hw *hw)
|
|
|
+{
|
|
|
+ struct clk_regmap *clk = to_clk_regmap(hw);
|
|
|
+ struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
|
|
|
+
|
|
|
+ /* Put the pll is in reset */
|
|
|
+ meson_parm_write(clk->map, &pll->rst, 1);
|
|
|
+
|
|
|
+ /* Disable the pll */
|
|
|
+ meson_parm_write(clk->map, &pll->en, 0);
|
|
|
+}
|
|
|
+
|
|
|
static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
|
|
unsigned long parent_rate)
|
|
|
{
|
|
|
struct clk_regmap *clk = to_clk_regmap(hw);
|
|
|
struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
|
|
|
const struct pll_rate_table *pllt;
|
|
|
+ unsigned int enabled;
|
|
|
unsigned long old_rate;
|
|
|
u16 frac = 0;
|
|
|
|
|
@@ -203,8 +236,9 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
|
|
if (!pllt)
|
|
|
return -EINVAL;
|
|
|
|
|
|
- /* Put the pll in reset to write the params */
|
|
|
- meson_parm_write(clk->map, &pll->rst, 1);
|
|
|
+ enabled = meson_parm_read(clk->map, &pll->en);
|
|
|
+ if (enabled)
|
|
|
+ meson_clk_pll_disable(hw);
|
|
|
|
|
|
meson_parm_write(clk->map, &pll->n, pllt->n);
|
|
|
meson_parm_write(clk->map, &pll->m, pllt->m);
|
|
@@ -221,10 +255,11 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
|
|
meson_parm_write(clk->map, &pll->frac, frac);
|
|
|
}
|
|
|
|
|
|
- /* make sure the reset is cleared at this point */
|
|
|
- meson_parm_write(clk->map, &pll->rst, 0);
|
|
|
+ /* If the pll is stopped, bail out now */
|
|
|
+ if (!enabled)
|
|
|
+ return 0;
|
|
|
|
|
|
- if (meson_clk_pll_wait_lock(hw)) {
|
|
|
+ if (meson_clk_pll_enable(hw)) {
|
|
|
pr_warn("%s: pll did not lock, trying to restore old rate %lu\n",
|
|
|
__func__, old_rate);
|
|
|
/*
|
|
@@ -244,6 +279,8 @@ const struct clk_ops meson_clk_pll_ops = {
|
|
|
.recalc_rate = meson_clk_pll_recalc_rate,
|
|
|
.round_rate = meson_clk_pll_round_rate,
|
|
|
.set_rate = meson_clk_pll_set_rate,
|
|
|
+ .enable = meson_clk_pll_enable,
|
|
|
+ .disable = meson_clk_pll_disable
|
|
|
};
|
|
|
|
|
|
const struct clk_ops meson_clk_pll_ro_ops = {
|