]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
clk: mediatek: clk-gate: Add ops for gates with HW voter
authorLaura Nao <laura.nao@collabora.com>
Mon, 15 Sep 2025 15:19:27 +0000 (17:19 +0200)
committerStephen Boyd <sboyd@kernel.org>
Sun, 21 Sep 2025 16:35:57 +0000 (09:35 -0700)
MT8196 use a HW voter for gate enable/disable control. Voting is
performed using set/clr regs, with a status bit used to verify the vote
state. Add new set of gate clock operations with support for voting via
set/clr regs.

Reviewed-by: NĂ­colas F. R. A. Prado <nfraprado@collabora.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Reviewed-by: Chen-Yu Tsai <wenst@chromium.org>
Signed-off-by: Laura Nao <laura.nao@collabora.com>
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
drivers/clk/mediatek/clk-gate.c
drivers/clk/mediatek/clk-gate.h

index 816e5f2d4079c2ca9cd6a09f21f73e7c9fab4b7f..f6b1429ff7578e157c2c705754d3cc3d4e6d874a 100644 (file)
@@ -5,6 +5,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/dev_printk.h>
 #include <linux/mfd/syscon.h>
 #include <linux/module.h>
 #include <linux/printk.h>
 #include <linux/slab.h>
 #include <linux/types.h>
 
+#include "clk-mtk.h"
 #include "clk-gate.h"
 
 struct mtk_clk_gate {
        struct clk_hw   hw;
        struct regmap   *regmap;
+       struct regmap   *regmap_hwv;
        const struct mtk_gate *gate;
 };
 
@@ -99,6 +102,32 @@ static void mtk_cg_disable_inv(struct clk_hw *hw)
        mtk_cg_clr_bit(hw);
 }
 
+static int mtk_cg_hwv_set_en(struct clk_hw *hw, bool enable)
+{
+       struct mtk_clk_gate *cg = to_mtk_clk_gate(hw);
+       u32 val;
+
+       regmap_write(cg->regmap_hwv,
+                    enable ? cg->gate->hwv_regs->set_ofs :
+                             cg->gate->hwv_regs->clr_ofs,
+                    BIT(cg->gate->shift));
+
+       return regmap_read_poll_timeout_atomic(cg->regmap_hwv,
+                                              cg->gate->hwv_regs->sta_ofs, val,
+                                              val & BIT(cg->gate->shift), 0,
+                                              MTK_WAIT_HWV_DONE_US);
+}
+
+static int mtk_cg_hwv_enable(struct clk_hw *hw)
+{
+       return mtk_cg_hwv_set_en(hw, true);
+}
+
+static void mtk_cg_hwv_disable(struct clk_hw *hw)
+{
+       mtk_cg_hwv_set_en(hw, false);
+}
+
 static int mtk_cg_enable_no_setclr(struct clk_hw *hw)
 {
        mtk_cg_clr_bit_no_setclr(hw);
@@ -123,6 +152,15 @@ static void mtk_cg_disable_inv_no_setclr(struct clk_hw *hw)
        mtk_cg_clr_bit_no_setclr(hw);
 }
 
+static bool mtk_cg_uses_hwv(const struct clk_ops *ops)
+{
+       if (ops == &mtk_clk_gate_hwv_ops_setclr ||
+           ops == &mtk_clk_gate_hwv_ops_setclr_inv)
+               return true;
+
+       return false;
+}
+
 const struct clk_ops mtk_clk_gate_ops_setclr = {
        .is_enabled     = mtk_cg_bit_is_cleared,
        .enable         = mtk_cg_enable,
@@ -137,6 +175,20 @@ const struct clk_ops mtk_clk_gate_ops_setclr_inv = {
 };
 EXPORT_SYMBOL_GPL(mtk_clk_gate_ops_setclr_inv);
 
+const struct clk_ops mtk_clk_gate_hwv_ops_setclr = {
+       .is_enabled     = mtk_cg_bit_is_cleared,
+       .enable         = mtk_cg_hwv_enable,
+       .disable        = mtk_cg_hwv_disable,
+};
+EXPORT_SYMBOL_GPL(mtk_clk_gate_hwv_ops_setclr);
+
+const struct clk_ops mtk_clk_gate_hwv_ops_setclr_inv = {
+       .is_enabled     = mtk_cg_bit_is_set,
+       .enable         = mtk_cg_hwv_enable,
+       .disable        = mtk_cg_hwv_disable,
+};
+EXPORT_SYMBOL_GPL(mtk_clk_gate_hwv_ops_setclr_inv);
+
 const struct clk_ops mtk_clk_gate_ops_no_setclr = {
        .is_enabled     = mtk_cg_bit_is_cleared,
        .enable         = mtk_cg_enable_no_setclr,
@@ -152,8 +204,9 @@ const struct clk_ops mtk_clk_gate_ops_no_setclr_inv = {
 EXPORT_SYMBOL_GPL(mtk_clk_gate_ops_no_setclr_inv);
 
 static struct clk_hw *mtk_clk_register_gate(struct device *dev,
-                                               const struct mtk_gate *gate,
-                                               struct regmap *regmap)
+                                           const struct mtk_gate *gate,
+                                           struct regmap *regmap,
+                                           struct regmap *regmap_hwv)
 {
        struct mtk_clk_gate *cg;
        int ret;
@@ -168,8 +221,13 @@ static struct clk_hw *mtk_clk_register_gate(struct device *dev,
        init.parent_names = gate->parent_name ? &gate->parent_name : NULL;
        init.num_parents = gate->parent_name ? 1 : 0;
        init.ops = gate->ops;
+       if (mtk_cg_uses_hwv(init.ops) && !regmap_hwv)
+               return dev_err_ptr_probe(
+                       dev, -ENXIO,
+                       "regmap not found for hardware voter clocks\n");
 
        cg->regmap = regmap;
+       cg->regmap_hwv = regmap_hwv;
        cg->gate = gate;
        cg->hw.init = &init;
 
@@ -201,6 +259,7 @@ int mtk_clk_register_gates(struct device *dev, struct device_node *node,
        int i;
        struct clk_hw *hw;
        struct regmap *regmap;
+       struct regmap *regmap_hwv;
 
        if (!clk_data)
                return -ENOMEM;
@@ -211,6 +270,12 @@ int mtk_clk_register_gates(struct device *dev, struct device_node *node,
                return PTR_ERR(regmap);
        }
 
+       regmap_hwv = mtk_clk_get_hwv_regmap(node);
+       if (IS_ERR(regmap_hwv))
+               return dev_err_probe(
+                       dev, PTR_ERR(regmap_hwv),
+                       "Cannot find hardware voter regmap for %pOF\n", node);
+
        for (i = 0; i < num; i++) {
                const struct mtk_gate *gate = &clks[i];
 
@@ -220,7 +285,7 @@ int mtk_clk_register_gates(struct device *dev, struct device_node *node,
                        continue;
                }
 
-               hw = mtk_clk_register_gate(dev, gate, regmap);
+               hw = mtk_clk_register_gate(dev, gate, regmap, regmap_hwv);
 
                if (IS_ERR(hw)) {
                        pr_err("Failed to register clk %s: %pe\n", gate->name,
index 1a46b4c56fc5d0a1cb4f16fd7a3fae8a3314271a..4f05b9855dae0c39fe238c8767de6aac2dab8769 100644 (file)
@@ -19,6 +19,8 @@ extern const struct clk_ops mtk_clk_gate_ops_setclr;
 extern const struct clk_ops mtk_clk_gate_ops_setclr_inv;
 extern const struct clk_ops mtk_clk_gate_ops_no_setclr;
 extern const struct clk_ops mtk_clk_gate_ops_no_setclr_inv;
+extern const struct clk_ops mtk_clk_gate_hwv_ops_setclr;
+extern const struct clk_ops mtk_clk_gate_hwv_ops_setclr_inv;
 
 struct mtk_gate_regs {
        u32 sta_ofs;
@@ -31,6 +33,7 @@ struct mtk_gate {
        const char *name;
        const char *parent_name;
        const struct mtk_gate_regs *regs;
+       const struct mtk_gate_regs *hwv_regs;
        int shift;
        const struct clk_ops *ops;
        unsigned long flags;