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

Reply via email to