Messages in this thread |  | | From | Chen-Yu Tsai <> | | Date | Fri, 5 Sep 2025 12:11:48 +0800 | | Subject | Re: [PATCH v5 05/27] clk: mediatek: clk-mux: Add ops for mux gates with HW voter and FENC |
| |
On Fri, Aug 29, 2025 at 5:21 PM Laura Nao <laura.nao@collabora.com> wrote: > > 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 <nfraprado@collabora.com> > Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> > Signed-off-by: Laura Nao <laura.nao@collabora.com> > --- > 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>
|  |