Re: [PATCH v5 05/27] clk: mediatek: clk-mux: Add ops for mux gates with HW voter and FENC
From: Chen-Yu Tsai <wenst@chromium.org>
Date: 2025-09-05 04:12:01
Also in:
linux-arm-kernel, linux-clk, linux-devicetree, linux-mediatek, lkml
On Fri, Aug 29, 2025 at 5:21 PM Laura Nao [off-list ref] wrote:
quoted hunk ↗ jump to hunk
MT8196 use a HW voter for mux gate enable/disable control, along with a FENC status bit to check the status. Voting is performed using set/clr/upd registers, with a status bit used to verify the vote state. Add new set of mux gate clock operations with support for voting via set/clr/upd regs and FENC status logic. Reviewed-by: Nícolas F. R. A. Prado <redacted> Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> Signed-off-by: Laura Nao <redacted> --- drivers/clk/mediatek/clk-mtk.h | 2 + drivers/clk/mediatek/clk-mux.c | 73 +++++++++++++++++++++++++++++++++- drivers/clk/mediatek/clk-mux.h | 42 +++++++++++++++++++ 3 files changed, 116 insertions(+), 1 deletion(-)diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h index 11962fac43ea..c381d6a6d908 100644 --- a/drivers/clk/mediatek/clk-mtk.h +++ b/drivers/clk/mediatek/clk-mtk.h@@ -20,6 +20,8 @@ #define MHZ (1000 * 1000) +#define MTK_WAIT_HWV_DONE_US 30 + struct platform_device; /*diff --git a/drivers/clk/mediatek/clk-mux.c b/drivers/clk/mediatek/clk-mux.c index 3931d157b262..2c2679e158e7 100644 --- a/drivers/clk/mediatek/clk-mux.c +++ b/drivers/clk/mediatek/clk-mux.c@@ -8,6 +8,7 @@ #include <linux/clk-provider.h> #include <linux/compiler_types.h> #include <linux/container_of.h> +#include <linux/dev_printk.h> #include <linux/err.h> #include <linux/mfd/syscon.h> #include <linux/module.h>@@ -15,6 +16,7 @@ #include <linux/spinlock.h> #include <linux/slab.h> +#include "clk-mtk.h" #include "clk-mux.h" #define MTK_WAIT_FENC_DONE_US 30@@ -22,6 +24,7 @@ struct mtk_clk_mux { struct clk_hw hw; struct regmap *regmap; + struct regmap *regmap_hwv; const struct mtk_mux *data; spinlock_t *lock; bool reparent;@@ -119,6 +122,41 @@ static int mtk_clk_mux_is_enabled(struct clk_hw *hw) return (val & BIT(mux->data->gate_shift)) == 0; } +static int mtk_clk_mux_hwv_fenc_enable(struct clk_hw *hw) +{ + struct mtk_clk_mux *mux = to_mtk_clk_mux(hw); + u32 val; + int ret; + + regmap_write(mux->regmap_hwv, mux->data->hwv_set_ofs, + BIT(mux->data->gate_shift)); + + ret = regmap_read_poll_timeout_atomic(mux->regmap_hwv, mux->data->hwv_sta_ofs, + val, val & BIT(mux->data->gate_shift), 0, + MTK_WAIT_HWV_DONE_US); + if (ret) + return ret; + + ret = regmap_read_poll_timeout_atomic(mux->regmap, mux->data->fenc_sta_mon_ofs, + val, val & BIT(mux->data->fenc_shift), 1, + MTK_WAIT_FENC_DONE_US); + + return ret; +} + +static void mtk_clk_mux_hwv_disable(struct clk_hw *hw) +{ + struct mtk_clk_mux *mux = to_mtk_clk_mux(hw); + u32 val; + + regmap_write(mux->regmap_hwv, mux->data->hwv_clr_ofs, + BIT(mux->data->gate_shift)); + + regmap_read_poll_timeout_atomic(mux->regmap_hwv, mux->data->hwv_sta_ofs, + val, (val & BIT(mux->data->gate_shift)), + 0, MTK_WAIT_HWV_DONE_US); +} + static u8 mtk_clk_mux_get_parent(struct clk_hw *hw) { struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);@@ -190,6 +228,14 @@ static int mtk_clk_mux_determine_rate(struct clk_hw *hw, return clk_mux_determine_rate_flags(hw, req, mux->data->flags); } +static bool mtk_clk_mux_uses_hwv(const struct clk_ops *ops) +{ + if (ops == &mtk_mux_gate_hwv_fenc_clr_set_upd_ops) + return true; + + return false; +} + 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,@@ -217,9 +263,20 @@ const struct clk_ops mtk_mux_gate_fenc_clr_set_upd_ops = { }; EXPORT_SYMBOL_GPL(mtk_mux_gate_fenc_clr_set_upd_ops); +const struct clk_ops mtk_mux_gate_hwv_fenc_clr_set_upd_ops = { + .enable = mtk_clk_mux_hwv_fenc_enable, + .disable = mtk_clk_mux_hwv_disable, + .is_enabled = mtk_clk_mux_fenc_is_enabled, + .get_parent = mtk_clk_mux_get_parent, + .set_parent = mtk_clk_mux_set_parent_setclr_lock, + .determine_rate = mtk_clk_mux_determine_rate, +}; +EXPORT_SYMBOL_GPL(mtk_mux_gate_hwv_fenc_clr_set_upd_ops); + static struct clk_hw *mtk_clk_register_mux(struct device *dev, const struct mtk_mux *mux, struct regmap *regmap, + struct regmap *regmap_hwv, spinlock_t *lock) { struct mtk_clk_mux *clk_mux;@@ -235,8 +292,14 @@ static struct clk_hw *mtk_clk_register_mux(struct device *dev, init.parent_names = mux->parent_names; init.num_parents = mux->num_parents; init.ops = mux->ops; + if (mtk_clk_mux_uses_hwv(init.ops) && !regmap_hwv) { + return dev_err_ptr_probe( + dev, -ENXIO, + "regmap not found for hardware voter clocks\n"); + }
Nit: The braces aren't really needed. But no need to respin just for this. Reviewed-by: Chen-Yu Tsai <wenst@chromium.org>