[PATCH 7/9] clk: meson: Support power-of-two dividers
Sean Anderson <[email protected]>
| Newsgroups | org.u-boot-project.lists.u-boot |
|---|---|
| Message-ID | <[email protected]> |
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, ...) \ -- 2.53.0