diff options
Diffstat (limited to 'drivers/clk/mediatek/clk-mux.c')
-rw-r--r-- | drivers/clk/mediatek/clk-mux.c | 89 |
1 files changed, 29 insertions, 60 deletions
diff --git a/drivers/clk/mediatek/clk-mux.c b/drivers/clk/mediatek/clk-mux.c index dcc1352bf13c..b0c61709bacc 100644 --- a/drivers/clk/mediatek/clk-mux.c +++ b/drivers/clk/mediatek/clk-mux.c @@ -17,29 +17,36 @@ static inline struct mtk_clk_mux *to_mtk_clk_mux(struct clk_hw *hw) return container_of(hw, struct mtk_clk_mux, hw); } -static int mtk_clk_mux_enable(struct clk_hw *hw) +static int mtk_clk_mux_enable_setclr(struct clk_hw *hw) { struct mtk_clk_mux *mux = to_mtk_clk_mux(hw); - u32 mask = BIT(mux->data->gate_shift); - - return regmap_update_bits(mux->regmap, mux->data->mux_ofs, - mask, ~mask); -} + unsigned long flags = 0; -static void mtk_clk_mux_disable(struct clk_hw *hw) -{ - struct mtk_clk_mux *mux = to_mtk_clk_mux(hw); - u32 mask = BIT(mux->data->gate_shift); + if (mux->lock) + spin_lock_irqsave(mux->lock, flags); + else + __acquire(mux->lock); - regmap_update_bits(mux->regmap, mux->data->mux_ofs, mask, mask); -} + regmap_write(mux->regmap, mux->data->clr_ofs, + BIT(mux->data->gate_shift)); + + /* + * If the parent has been changed when the clock was disabled, it will + * not be effective yet. Set the update bit to ensure the mux gets + * updated. + */ + if (mux->reparent && mux->data->upd_shift >= 0) { + regmap_write(mux->regmap, mux->data->upd_ofs, + BIT(mux->data->upd_shift)); + mux->reparent = false; + } -static int mtk_clk_mux_enable_setclr(struct clk_hw *hw) -{ - struct mtk_clk_mux *mux = to_mtk_clk_mux(hw); + if (mux->lock) + spin_unlock_irqrestore(mux->lock, flags); + else + __release(mux->lock); - return regmap_write(mux->regmap, mux->data->clr_ofs, - BIT(mux->data->gate_shift)); + return 0; } static void mtk_clk_mux_disable_setclr(struct clk_hw *hw) @@ -72,28 +79,6 @@ static u8 mtk_clk_mux_get_parent(struct clk_hw *hw) return val; } -static int mtk_clk_mux_set_parent_lock(struct clk_hw *hw, u8 index) -{ - struct mtk_clk_mux *mux = to_mtk_clk_mux(hw); - u32 mask = GENMASK(mux->data->mux_width - 1, 0); - unsigned long flags = 0; - - if (mux->lock) - spin_lock_irqsave(mux->lock, flags); - else - __acquire(mux->lock); - - regmap_update_bits(mux->regmap, mux->data->mux_ofs, mask, - index << mux->data->mux_shift); - - if (mux->lock) - spin_unlock_irqrestore(mux->lock, flags); - else - __release(mux->lock); - - return 0; -} - static int mtk_clk_mux_set_parent_setclr_lock(struct clk_hw *hw, u8 index) { struct mtk_clk_mux *mux = to_mtk_clk_mux(hw); @@ -116,9 +101,11 @@ static int mtk_clk_mux_set_parent_setclr_lock(struct clk_hw *hw, u8 index) regmap_write(mux->regmap, mux->data->set_ofs, index << mux->data->mux_shift); - if (mux->data->upd_shift >= 0) + if (mux->data->upd_shift >= 0) { regmap_write(mux->regmap, mux->data->upd_ofs, BIT(mux->data->upd_shift)); + mux->reparent = true; + } } if (mux->lock) @@ -129,25 +116,7 @@ static int mtk_clk_mux_set_parent_setclr_lock(struct clk_hw *hw, u8 index) return 0; } -const struct clk_ops mtk_mux_ops = { - .get_parent = mtk_clk_mux_get_parent, - .set_parent = mtk_clk_mux_set_parent_lock, -}; - -const struct clk_ops mtk_mux_clr_set_upd_ops = { - .get_parent = mtk_clk_mux_get_parent, - .set_parent = mtk_clk_mux_set_parent_setclr_lock, -}; - -const struct clk_ops mtk_mux_gate_ops = { - .enable = mtk_clk_mux_enable, - .disable = mtk_clk_mux_disable, - .is_enabled = mtk_clk_mux_is_enabled, - .get_parent = mtk_clk_mux_get_parent, - .set_parent = mtk_clk_mux_set_parent_lock, -}; - -const struct clk_ops mtk_mux_gate_clr_set_upd_ops = { +static const struct clk_ops mtk_mux_ops = { .enable = mtk_clk_mux_enable_setclr, .disable = mtk_clk_mux_disable_setclr, .is_enabled = mtk_clk_mux_is_enabled, @@ -171,7 +140,7 @@ static struct clk *mtk_clk_register_mux(const struct mtk_mux *mux, init.flags = mux->flags | CLK_SET_RATE_PARENT; init.parent_names = mux->parent_names; init.num_parents = mux->num_parents; - init.ops = mux->ops; + init.ops = &mtk_mux_ops; clk_mux->regmap = regmap; clk_mux->data = mux; |