diff options
Diffstat (limited to 'drivers/clk/nxp')
-rw-r--r-- | drivers/clk/nxp/clk-lpc18xx-ccu.c | 17 | ||||
-rw-r--r-- | drivers/clk/nxp/clk-lpc18xx-cgu.c | 42 |
2 files changed, 54 insertions, 5 deletions
diff --git a/drivers/clk/nxp/clk-lpc18xx-ccu.c b/drivers/clk/nxp/clk-lpc18xx-ccu.c index eeaee97da..13aabbb3a 100644 --- a/drivers/clk/nxp/clk-lpc18xx-ccu.c +++ b/drivers/clk/nxp/clk-lpc18xx-ccu.c @@ -179,9 +179,22 @@ static void lpc18xx_ccu_gate_disable(struct clk_hw *hw) static int lpc18xx_ccu_gate_is_enabled(struct clk_hw *hw) { - struct clk_gate *gate = to_clk_gate(hw); + const struct clk_hw *parent; + + /* + * The branch clock registers are only accessible + * if the base (parent) clock is enabled. Register + * access with a disabled base clock will hang the + * system. + */ + parent = clk_hw_get_parent(hw); + if (!parent) + return 0; + + if (!clk_hw_is_enabled(parent)) + return 0; - return clk_readl(gate->reg) & LPC18XX_CCU_RUN; + return clk_gate_ops.is_enabled(hw); } static const struct clk_ops lpc18xx_ccu_gate_ops = { diff --git a/drivers/clk/nxp/clk-lpc18xx-cgu.c b/drivers/clk/nxp/clk-lpc18xx-cgu.c index e0a3cb897..c924572fc 100644 --- a/drivers/clk/nxp/clk-lpc18xx-cgu.c +++ b/drivers/clk/nxp/clk-lpc18xx-cgu.c @@ -480,6 +480,42 @@ static const struct clk_ops lpc18xx_pll1_ops = { .recalc_rate = lpc18xx_pll1_recalc_rate, }; +static int lpc18xx_cgu_gate_enable(struct clk_hw *hw) +{ + return clk_gate_ops.enable(hw); +} + +static void lpc18xx_cgu_gate_disable(struct clk_hw *hw) +{ + clk_gate_ops.disable(hw); +} + +static int lpc18xx_cgu_gate_is_enabled(struct clk_hw *hw) +{ + const struct clk_hw *parent; + + /* + * The consumer of base clocks needs know if the + * base clock is really enabled before it can be + * accessed. It is therefore necessary to verify + * this all the way up. + */ + parent = clk_hw_get_parent(hw); + if (!parent) + return 0; + + if (!clk_hw_is_enabled(parent)) + return 0; + + return clk_gate_ops.is_enabled(hw); +} + +static const struct clk_ops lpc18xx_gate_ops = { + .enable = lpc18xx_cgu_gate_enable, + .disable = lpc18xx_cgu_gate_disable, + .is_enabled = lpc18xx_cgu_gate_is_enabled, +}; + static struct lpc18xx_cgu_pll_clk lpc18xx_cgu_src_clk_plls[] = { LPC1XX_CGU_CLK_PLL(PLL0USB, pll0_src_ids, pll0_ops), LPC1XX_CGU_CLK_PLL(PLL0AUDIO, pll0_src_ids, pll0_ops), @@ -510,7 +546,7 @@ static struct clk *lpc18xx_cgu_register_div(struct lpc18xx_cgu_src_clk_div *clk, return clk_register_composite(NULL, name, parents, clk->n_parents, &clk->mux.hw, &clk_mux_ops, &clk->div.hw, &clk_divider_ops, - &clk->gate.hw, &clk_gate_ops, 0); + &clk->gate.hw, &lpc18xx_gate_ops, 0); } @@ -538,7 +574,7 @@ static struct clk *lpc18xx_register_base_clk(struct lpc18xx_cgu_base_clk *clk, return clk_register_composite(NULL, name, parents, clk->n_parents, &clk->mux.hw, &clk_mux_ops, NULL, NULL, - &clk->gate.hw, &clk_gate_ops, 0); + &clk->gate.hw, &lpc18xx_gate_ops, 0); } @@ -557,7 +593,7 @@ static struct clk *lpc18xx_cgu_register_pll(struct lpc18xx_cgu_pll_clk *clk, return clk_register_composite(NULL, name, parents, clk->n_parents, &clk->mux.hw, &clk_mux_ops, &clk->pll.hw, clk->pll_ops, - &clk->gate.hw, &clk_gate_ops, 0); + &clk->gate.hw, &lpc18xx_gate_ops, 0); } static void __init lpc18xx_cgu_register_source_clks(struct device_node *np, |