[PATCH v7 05/22] clk: Add functions to register CCF clock structs

Rick Chen
2020-03-30T07:05:23Z

Hi Peng and Lukasz

> 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>
> ---
>
> 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(-)
>

Do you have any comments about this patch ?

Thanks
Rick

> 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.1
>