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

Reply via email to