
Hi Sean
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 seanga2@gmail.com
This is a new patch since v5 and still lack of tag of MAINTAINERs. I will prefer to exclude it in the later pull request of riscv tree.
Thanks, Rick
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