This patch adds alternate versions of the clk_*_register functions for use
with statically-allocated struct clks. This allows drivers to define clocks
at compile-time and register them at run-time without malloc-ing. This
increases the size of the binary, but should not affect ram usage (since
the clocks now no longer live on the heap).

Signed-off-by: Sean Anderson <sean...@gmail.com>
---

Changes in v5:
- New

 drivers/clk/clk-composite.c  | 103 +++++++++++++++++++----------------
 drivers/clk/clk-divider.c    |  56 +++++++++----------
 drivers/clk/clk-gate.c       |  38 ++++++++-----
 include/linux/clk-provider.h |   9 +++
 4 files changed, 112 insertions(+), 94 deletions(-)

diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c
index 819bfca2fc..b328c4e5a5 100644
--- a/drivers/clk/clk-composite.c
+++ b/drivers/clk/clk-composite.c
@@ -95,6 +95,51 @@ static int clk_composite_disable(struct clk *clk)
                return 0;
 }
 
+struct clk *clk_register_composite_struct(const char *name,
+                                         const char * const *parent_names,
+                                         int num_parents,
+                                         struct clk_composite *composite)
+{
+       int ret;
+       struct clk *clk;
+
+       if (!num_parents || (num_parents != 1 && !composite->mux))
+               return ERR_PTR(-EINVAL);
+
+       if (composite->mux && composite->mux_ops)
+               composite->mux->data = (ulong)composite;
+
+       if (composite->rate && composite->rate_ops) {
+               if (!composite->rate_ops->get_rate)
+                       return ERR_PTR(-EINVAL);
+
+               composite->rate->data = (ulong)composite;
+       }
+
+       if (composite->gate && composite->gate_ops) {
+               if (!composite->gate_ops->enable ||
+                   !composite->gate_ops->disable)
+                       return ERR_PTR(-EINVAL);
+
+               composite->gate->data = (ulong)composite;
+       }
+
+       clk = &composite->clk;
+       ret = clk_register(clk, UBOOT_DM_CLK_COMPOSITE, name,
+                          parent_names[clk_composite_get_parent(clk)]);
+       if (ret)
+               clk = ERR_PTR(ret);
+
+       if (composite->mux)
+               composite->mux->dev = clk->dev;
+       if (composite->rate)
+               composite->rate->dev = clk->dev;
+       if (composite->gate)
+               composite->gate->dev = clk->dev;
+
+       return clk;
+}
+
 struct clk *clk_register_composite(struct device *dev, const char *name,
                                   const char * const *parent_names,
                                   int num_parents, struct clk *mux,
@@ -107,62 +152,24 @@ struct clk *clk_register_composite(struct device *dev, 
const char *name,
 {
        struct clk *clk;
        struct clk_composite *composite;
-       int ret;
-
-       if (!num_parents || (num_parents != 1 && !mux))
-               return ERR_PTR(-EINVAL);
 
        composite = kzalloc(sizeof(*composite), GFP_KERNEL);
        if (!composite)
                return ERR_PTR(-ENOMEM);
 
-       if (mux && mux_ops) {
-               composite->mux = mux;
-               composite->mux_ops = mux_ops;
-               mux->data = (ulong)composite;
-       }
+       composite->mux = mux;
+       composite->mux_ops = mux_ops;
 
-       if (rate && rate_ops) {
-               if (!rate_ops->get_rate) {
-                       clk = ERR_PTR(-EINVAL);
-                       goto err;
-               }
+       composite->rate = rate;
+       composite->rate_ops = rate_ops;
 
-               composite->rate = rate;
-               composite->rate_ops = rate_ops;
-               rate->data = (ulong)composite;
-       }
+       composite->gate = gate;
+       composite->gate_ops = gate_ops;
 
-       if (gate && gate_ops) {
-               if (!gate_ops->enable || !gate_ops->disable) {
-                       clk = ERR_PTR(-EINVAL);
-                       goto err;
-               }
-
-               composite->gate = gate;
-               composite->gate_ops = gate_ops;
-               gate->data = (ulong)composite;
-       }
-
-       clk = &composite->clk;
-       ret = clk_register(clk, UBOOT_DM_CLK_COMPOSITE, name,
-                          parent_names[clk_composite_get_parent(clk)]);
-       if (ret) {
-               clk = ERR_PTR(ret);
-               goto err;
-       }
-
-       if (composite->mux)
-               composite->mux->dev = clk->dev;
-       if (composite->rate)
-               composite->rate->dev = clk->dev;
-       if (composite->gate)
-               composite->gate->dev = clk->dev;
-
-       return clk;
-
-err:
-       kfree(composite);
+       clk = clk_register_composite_struct(name, parent_names, num_parents,
+                                           composite);
+       if (IS_ERR(clk))
+               kfree(composite);
        return clk;
 }
 
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index 5fe1c3941f..747504d0a0 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -178,22 +178,37 @@ const struct clk_ops clk_divider_ops = {
        .set_rate = clk_divider_set_rate,
 };
 
-static struct clk *_register_divider(struct device *dev, const char *name,
-               const char *parent_name, unsigned long flags,
-               void __iomem *reg, u8 shift, u8 width,
-               u8 clk_divider_flags, const struct clk_div_table *table)
+struct clk *clk_register_divider_struct(const char *name,
+                                       const char *parent_name,
+                                       struct clk_divider *div)
 {
-       struct clk_divider *div;
-       struct clk *clk;
        int ret;
+       struct clk *clk;
 
-       if (clk_divider_flags & CLK_DIVIDER_HIWORD_MASK) {
-               if (width + shift > 16) {
+       if (div->flags & CLK_DIVIDER_HIWORD_MASK) {
+               if (div->width + div->shift > 16) {
                        pr_warn("divider value exceeds LOWORD field\n");
                        return ERR_PTR(-EINVAL);
                }
        }
 
+       /* register the clock */
+       clk = &div->clk;
+
+       ret = clk_register(clk, UBOOT_DM_CLK_CCF_DIVIDER, name, parent_name);
+       if (ret)
+               return ERR_PTR(ret);
+       return clk;
+}
+
+struct clk *clk_register_divider(struct device *dev, const char *name,
+                                const char *parent_name, unsigned long flags,
+                                void __iomem *reg, u8 shift, u8 width,
+                                u8 clk_divider_flags)
+{
+       struct clk_divider *div;
+       struct clk *clk;
+
        /* allocate the divider */
        div = kzalloc(sizeof(*div), GFP_KERNEL);
        if (!div)
@@ -204,34 +219,13 @@ static struct clk *_register_divider(struct device *dev, 
const char *name,
        div->shift = shift;
        div->width = width;
        div->flags = clk_divider_flags;
-       div->table = table;
 #if CONFIG_IS_ENABLED(SANDBOX_CLK_CCF)
        div->io_divider_val = *(u32 *)reg;
 #endif
 
-       /* register the clock */
-       clk = &div->clk;
-
-       ret = clk_register(clk, UBOOT_DM_CLK_CCF_DIVIDER, name, parent_name);
-       if (ret) {
-               kfree(div);
-               return ERR_PTR(ret);
-       }
-
-       return clk;
-}
-
-struct clk *clk_register_divider(struct device *dev, const char *name,
-               const char *parent_name, unsigned long flags,
-               void __iomem *reg, u8 shift, u8 width,
-               u8 clk_divider_flags)
-{
-       struct clk *clk;
-
-       clk =  _register_divider(dev, name, parent_name, flags, reg, shift,
-                                width, clk_divider_flags, NULL);
+       clk = clk_register_divider_struct(name, parent_name, div);
        if (IS_ERR(clk))
-               return ERR_CAST(clk);
+               kfree(div);
        return clk;
 }
 
diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c
index b5827dced0..82445d2ccb 100644
--- a/drivers/clk/clk-gate.c
+++ b/drivers/clk/clk-gate.c
@@ -111,6 +111,27 @@ const struct clk_ops clk_gate_ops = {
        .get_rate = clk_generic_get_rate,
 };
 
+struct clk *clk_register_gate_struct(const char *name, const char *parent_name,
+                                    struct clk_gate *gate)
+{
+       int ret;
+       struct clk *clk;
+
+       if (gate->flags & CLK_GATE_HIWORD_MASK) {
+               if (gate->bit_idx > 15) {
+                       pr_err("gate bit exceeds LOWORD field\n");
+                       return ERR_PTR(-EINVAL);
+               }
+       }
+
+       clk = &gate->clk;
+
+       ret = clk_register(clk, UBOOT_DM_CLK_GATE, name, parent_name);
+       if (ret)
+               return ERR_PTR(ret);
+       return clk;
+}
+
 struct clk *clk_register_gate(struct device *dev, const char *name,
                              const char *parent_name, unsigned long flags,
                              void __iomem *reg, u8 bit_idx,
@@ -118,14 +139,6 @@ struct clk *clk_register_gate(struct device *dev, const 
char *name,
 {
        struct clk_gate *gate;
        struct clk *clk;
-       int ret;
-
-       if (clk_gate_flags & CLK_GATE_HIWORD_MASK) {
-               if (bit_idx > 15) {
-                       pr_err("gate bit exceeds LOWORD field\n");
-                       return ERR_PTR(-EINVAL);
-               }
-       }
 
        /* allocate the gate */
        gate = kzalloc(sizeof(*gate), GFP_KERNEL);
@@ -140,14 +153,9 @@ struct clk *clk_register_gate(struct device *dev, const 
char *name,
        gate->io_gate_val = *(u32 *)reg;
 #endif
 
-       clk = &gate->clk;
-
-       ret = clk_register(clk, UBOOT_DM_CLK_GATE, name, parent_name);
-       if (ret) {
+       clk = clk_register_gate_struct(name, parent_name, gate);
+       if (IS_ERR(clk))
                kfree(gate);
-               return ERR_PTR(ret);
-       }
-
        return clk;
 }
 
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 8a20743ad8..8bf8dca0a3 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -95,6 +95,8 @@ struct clk *clk_register_gate(struct device *dev, const char 
*name,
                              const char *parent_name, unsigned long flags,
                              void __iomem *reg, u8 bit_idx,
                              u8 clk_gate_flags, spinlock_t *lock);
+struct clk *clk_register_gate_struct(const char *name, const char *parent_name,
+                                    struct clk_gate *gate);
 
 struct clk_div_table {
        unsigned int    val;
@@ -166,6 +168,10 @@ struct clk *clk_register_composite(struct device *dev, 
const char *name,
                struct clk *rate_clk, const struct clk_ops *rate_ops,
                struct clk *gate_clk, const struct clk_ops *gate_ops,
                unsigned long flags);
+struct clk *clk_register_composite_struct(const char *name,
+                                         const char * const *parent_names,
+                                         int num_parents,
+                                         struct clk_composite *composite);
 
 int clk_register(struct clk *clk, const char *drv_name, const char *name,
                 const char *parent_name);
@@ -178,6 +184,9 @@ struct clk *clk_register_divider(struct device *dev, const 
char *name,
                const char *parent_name, unsigned long flags,
                void __iomem *reg, u8 shift, u8 width,
                u8 clk_divider_flags);
+struct clk *clk_register_divider_struct(const char *name,
+                                       const char *parent_name,
+                                       struct clk_divider *div);
 
 struct clk *clk_register_mux(struct device *dev, const char *name,
                const char * const *parent_names, u8 num_parents,
-- 
2.25.0

Reply via email to