Re: [PATCH 7/9] clk: meson: Support power-of-two dividers
Neil Armstrong <[email protected]>
| Newsgroups | org.u-boot-project.lists.u-boot,io.groups.u-boot-amlogic |
|---|---|
| Organization | Linaro |
| Message-ID | <[email protected]> |
On 8/17/26 19:15, Sean Anderson wrote: > Several s4 clocks use power-of-two dividers. Add support for them. > > Signed-off-by: Sean Anderson <[email protected]> > --- > > drivers/clk/meson/clk_meson.c | 49 ++++++++++++++++++++++++++--------- > drivers/clk/meson/clk_meson.h | 44 +++++++++++++++---------------- > 2 files changed, 59 insertions(+), 34 deletions(-) > > diff --git a/drivers/clk/meson/clk_meson.c b/drivers/clk/meson/clk_meson.c > index 29615fdae77..50c72276457 100644 > --- a/drivers/clk/meson/clk_meson.c > +++ b/drivers/clk/meson/clk_meson.c > @@ -55,26 +55,49 @@ int meson_clk_disable(struct clk *clk) > return meson_set_gate(clk, false); > } > > +static ulong meson_div_get_rate_common(struct clk *clk, > + enum meson_clk_type type, u16 *n, > + ulong *rate) > +{ > + struct meson_clk *priv = dev_get_priv(clk->dev); > + const struct meson_clk_info *info; > + struct clk parent; > + > + info = meson_clk_get_info(clk, type); > + if (IS_ERR(info)) > + return PTR_ERR(info); > + > + *n = GET_PARM_VALUE(priv, info->parm); > + > + parent.dev = clk->dev; > + parent.id = info->parents[0]; > + *rate = meson_clk_get_rate(&parent); > + return 0; > +} > + > static ulong meson_div_get_rate(struct clk *clk) > { > - struct meson_clk *priv = dev_get_priv(clk->dev); > + ulong rate, err; > u16 n; > - ulong rate; > - const struct meson_clk_info *info; > - struct clk parent; > > - info = meson_clk_get_info(clk, MESON_CLK_DIV); > - if (IS_ERR(info)) > - return PTR_ERR(info); > + err = meson_div_get_rate_common(clk, MESON_CLK_DIV, &n, &rate); > + if (err) > + return err; > > /* Actual divider value is (field value + 1), hence the increment */ > - n = GET_PARM_VALUE(priv, info->parm) + 1; > + return rate / (n + 1); > +} > > - parent.dev = clk->dev; > - parent.id = info->parents[0]; > - rate = meson_clk_get_rate(&parent); > +static ulong meson_div2_get_rate(struct clk *clk) > +{ > + ulong rate, err; > + u16 n; > > - return rate / n; > + err = meson_div_get_rate_common(clk, MESON_CLK_DIV2, &n, &rate); > + if (err) > + return err; > + > + return rate >> n; > } > > int meson_clk_get_parent(struct clk *clk) > @@ -150,6 +173,8 @@ ulong meson_clk_get_rate(struct clk *clk) > return meson_clk_get_rate(&parent); > case MESON_CLK_DIV: > return meson_div_get_rate(clk); > + case MESON_CLK_DIV2: > + return meson_div2_get_rate(clk); > case MESON_CLK_FIXED_DIV: > parent.dev = clk->dev; > parent.id = meson_clk_get_parent(clk); > diff --git a/drivers/clk/meson/clk_meson.h b/drivers/clk/meson/clk_meson.h > index 86b272985ab..46ee5519410 100644 > --- a/drivers/clk/meson/clk_meson.h > +++ b/drivers/clk/meson/clk_meson.h > @@ -61,6 +61,7 @@ struct meson_clk { > * @MESON_CLK_GATE: This clock is a gate > * @MESON_CLK_MUX: This clock is a multiplexer > * @MESON_CLK_DIV: This clock is a configurable divider > + * @MESON_CLK_DIV2: This clock is a configurable power-of-two divider > * @MESON_CLK_FIXED_DIV: This clock is a (fractional) fixed-factor clock > * @MESON_CLK_EXTERNAL: This is an external clock from different clock provider > * @MESON_CLK_PLL: This is a PLL > @@ -70,6 +71,7 @@ enum meson_clk_type { > MESON_CLK_GATE, > MESON_CLK_MUX, > MESON_CLK_DIV, > + MESON_CLK_DIV2, > MESON_CLK_FIXED_DIV, > MESON_CLK_EXTERNAL, > MESON_CLK_PLL, > @@ -122,18 +124,25 @@ struct meson_clk_data { > .type = MESON_CLK_MUX, \ > }) > > +#define _CLK_REG(_type, _name, _reg, _shift, _width, _parent) \ > + (&(struct meson_clk_info){ \ > + .parents = (const unsigned int[]) { (_parent) }, \ > + .parm = &(struct parm) { \ > + .reg_off = (_reg), \ > + .shift = (_shift), \ > + .width = (_width), \ > + }, \ > + .name = (_name), \ > + .type = _type, \ > + }) > + > /* A divider with an integral divisor */ > -#define CLK_DIV(_name, _reg, _shift, _width, _parent) \ > - (&(struct meson_clk_info){ \ > - .parents = (const unsigned int[]) { (_parent) }, \ > - .parm = &(struct parm) { \ > - .reg_off = (_reg), \ > - .shift = (_shift), \ > - .width = (_width), \ > - }, \ > - .name = (_name), \ > - .type = MESON_CLK_DIV, \ > - }) > +#define CLK_DIV(name, reg, shift, width, parent) \ > + _CLK_REG(MESON_CLK_DIV, name, reg, shift, width, parent) > + > +/* A divider with a power-of-two divisor */ > +#define CLK_DIV2(name, reg, shift, width, parent) \ > + _CLK_REG(MESON_CLK_DIV2, name, reg, shift, width, parent) > > /* A fixed divider */ > #define CLK_DIV_FIXED_FULL(_name, _mult, _div, _parent) \ > @@ -156,17 +165,8 @@ struct meson_clk_data { > }) > > /* A clock gate */ > -#define CLK_GATE(_name, _reg, _shift, _parent) \ > - (&(struct meson_clk_info){ \ > - .parents = (const unsigned int[]) { (_parent) }, \ > - .parm = &(struct parm) { \ > - .reg_off = (_reg), \ > - .shift = (_shift), \ > - .width = 1, \ > - }, \ > - .name = (_name), \ > - .type = MESON_CLK_GATE, \ > - }) > +#define CLK_GATE(name, reg, shift, parent) \ > + _CLK_REG(MESON_CLK_GATE, name, reg, shift, 1, parent) > > /* A PLL clock */ > #define CLK_PLL(_name, _parent, ...) \ Reviewed-by: Neil Armstrong <[email protected]> Thanks, Neil