clk: mediatek: mux: Update parent at enable time
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Mon, 25 Jan 2021 17:08:19 +0000 (19:08 +0200)
committerStephen Boyd <sboyd@kernel.org>
Tue, 9 Feb 2021 08:01:28 +0000 (00:01 -0800)
The mux clocks don't always correctly take the new parent into account
when the parent is updated while the clock is disabled. Set the update
bit when enabling the clock to force an update of the mux.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Link: https://lore.kernel.org/r/20210125170819.26130-3-laurent.pinchart@ideasonboard.com
Reviewed-by: Weiyi Lu <weiyi.lu@mediatek.com>
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
drivers/clk/mediatek/clk-mux.c
drivers/clk/mediatek/clk-mux.h

index 9370bebca7f8ac8665a18ea5cede25a269b722ab..b0c61709bacc2a57a54b0b878dbf631b0f421f1a 100644 (file)
@@ -20,9 +20,33 @@ static inline struct mtk_clk_mux *to_mtk_clk_mux(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);
+       unsigned long flags = 0;
 
-       return regmap_write(mux->regmap, mux->data->clr_ofs,
-                       BIT(mux->data->gate_shift));
+       if (mux->lock)
+               spin_lock_irqsave(mux->lock, flags);
+       else
+               __acquire(mux->lock);
+
+       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;
+       }
+
+       if (mux->lock)
+               spin_unlock_irqrestore(mux->lock, flags);
+       else
+               __release(mux->lock);
+
+       return 0;
 }
 
 static void mtk_clk_mux_disable_setclr(struct clk_hw *hw)
@@ -77,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)
index 15c62366ba9a3326f093a71d5f9479dfaf3191ce..f1946161ade14107a836070ac7af810e46df82be 100644 (file)
@@ -14,6 +14,7 @@ struct mtk_clk_mux {
        struct regmap *regmap;
        const struct mtk_mux *data;
        spinlock_t *lock;
+       bool reparent;
 };
 
 struct mtk_mux {