[PATCH v6 08/15] clk: starfive: Introduce idiv ops for inverted divider clocks
Changhuang Liang
changhuang.liang at starfivetech.com
Tue Oct 13 20:16:13 PDT 2026
Hi, Jerome
> > Some StarFive clocks only advertise the divider and invert
> > capabilities (via JH71X0_CLK_INVERT, without ENABLE). Add the
> > JH71X0_IDIV() macro to declare such clocks, and jh71x0_clk_idiv_ops,
> > which combines the divider rate operations with get_phase/set_phase.
> >
>
> Please rephrase, I don't understand what you mean
>
> > Signed-off-by: Changhuang Liang <changhuang.liang at starfivetech.com>
> > ---
> > drivers/clk/starfive/clk-starfive-jh71x0.c | 13 ++++++++++++-
> > drivers/clk/starfive/clk-starfive-jh71x0.h | 8 ++++++++
> > 2 files changed, 20 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/clk/starfive/clk-starfive-jh71x0.c
> > b/drivers/clk/starfive/clk-starfive-jh71x0.c
> > index c5ee82db3c92..224fcc3d08db 100644
> > --- a/drivers/clk/starfive/clk-starfive-jh71x0.c
> > +++ b/drivers/clk/starfive/clk-starfive-jh71x0.c
> > @@ -303,6 +303,15 @@ static const struct clk_ops jh71x0_clk_inv_ops = {
> > .debug_init = jh71x0_clk_debug_init, };
> >
> > +static const struct clk_ops jh71x0_clk_idiv_ops = {
> > + .get_phase = jh71x0_clk_get_phase,
> > + .set_phase = jh71x0_clk_set_phase,
> > + .recalc_rate = jh71x0_clk_recalc_rate,
> > + .determine_rate = jh71x0_clk_determine_rate,
> > + .set_rate = jh71x0_clk_set_rate,
> > + .debug_init = jh71x0_clk_debug_init,
>
> Instead of trying to cover all the combination that could exist, can you just
> chain 2 elements ?
> a div then an inv ?
This may require introducing quite a few new changes.
In the current code, struct clk_hw *hw is used to obtain struct jh71x0_clk *clk through hw, and then the register offset is obtained through clk->idx.
static void jh71x0_clk_reg_rmw(struct jh71x0_clk *clk, u32 mask, u32 value)
{
struct jh71x0_clk_priv *priv = jh71x0_priv_from(clk);
void __iomem *reg = priv->base + 4 * clk->idx;
unsigned long flags;
spin_lock_irqsave(&priv->rmw_lock, flags);
value |= readl_relaxed(reg) & ~mask;
writel_relaxed(value, reg);
spin_unlock_irqrestore(&priv->rmw_lock, flags);
}
static int jh71x0_clk_enable(struct clk_hw *hw)
{
struct jh71x0_clk *clk = jh71x0_clk_from(hw);
jh71x0_clk_reg_rmw(clk, JH71X0_CLK_ENABLE, JH71X0_CLK_ENABLE);
return 0;
}
Therefore, the existing code has one struct clk_hw corresponding to one register offset.
If it is split into a div and an inv, two struct clk_hw descriptions will be needed.
The jh71x0_crg_probe() will need to implement different branches for different clocks:
if (a div and an inv) {
devm_clk_hw_register (div)
devm_clk_hw_register (inv)
} else {
devm_clk_hw_register (other)
}
Do you need me to make this part of the adjustment?
> > +};
> > +
> > const struct clk_ops *starfive_jh71x0_clk_ops(u32 max) {
> > if (max & JH71X0_CLK_DIV_MASK) {
> > @@ -313,7 +322,9 @@ const struct clk_ops *starfive_jh71x0_clk_ops(u32
> max)
> > }
> > if (max & JH71X0_CLK_ENABLE)
> > return &jh71x0_clk_gdiv_ops;
> > - if (max == JH71X0_CLK_FRAC_MAX)
> > + else if (max & JH71X0_CLK_INVERT)
> > + return &jh71x0_clk_idiv_ops;
> > + else if (max == JH71X0_CLK_FRAC_MAX)
> > return &jh71x0_clk_fdiv_ops;
>
> Given the branches return, if was enough and you did not need to modify the
> existing path.
>
Best Regards,
Changhuang
More information about the linux-riscv
mailing list