Re: [RFC PATCH v2 10/30] drivers/clk: SH7750 / SH7751 CPG Driver

Geert Uytterhoeven <[email protected]>
Newsgroups gmane.linux.kernel.clk,gmane.linux.ports.sh.devel
Message-ID <CAMuHMdWwGdEJrfuVvwOCL34OmmbkkO=DQeSoqWDkSjxub=00sQ@mail.gmail.com>
Hi Sato-san,

On Wed, Sep 13, 2023 at 11:25 AM Yoshinori Sato
<[email protected]> wrote:
> Signed-off-by: Yoshinori Sato <[email protected]>

Thanks for your patch!

>  drivers/clk/renesas/clk-sh7750.c | 236 +++++++++++++++++++++++++++++++

Patch prefix should be "clk: renesas: ".

> --- /dev/null
> +++ b/drivers/clk/renesas/clk-sh7750.c
> @@ -0,0 +1,236 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Renesas SH7750/51 CPG driver
> + *
> + * Copyright 2023 Yoshinori Sato <[email protected]>
> + */
> +
> +#include <linux/clkdev.h>
> +#include <linux/clk-provider.h>
> +#include <linux/err.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/io.h>

Please add a blank line.

> +#include "clk-shdiv.h"

This doesn't exist until "[RFC PATCH v2 11/30] drivers/clk: SuperH
generai clock divider helper", so please move that patch up in the
series.

> +#include <dt-bindings/clock/sh7750.h>

This doesn't exist until "[RFC PATCH v2 24/30] include/dt-bindings:
Add SH7750 CPG header.", so please move that patch up in the series.

> +
> +static DEFINE_SPINLOCK(clklock);

I think it would make sense to move this into struct cpg_priv.


> +struct cpg_priv {
> +       struct clk_hw hw;
> +       void __iomem *frqcr;
> +       void __iomem *wdt;
> +       u32 mode;
> +       bool have_div1;
> +};
> +
> +#define to_priv(_hw) container_of(_hw, struct cpg_priv, hw)
> +
> +#define FRQCR_PLL1EN BIT(10)
> +static const int pll1mult[] = { 12, 12, 6, 12, 6, 12, 1};

unsigned int

> +
> +static unsigned long pll_recalc_rate(struct clk_hw *hw,
> +                                     unsigned long parent_rate)
> +{
> +       struct cpg_priv *cpg = to_priv(hw);
> +       unsigned long rate = parent_rate;
> +       uint16_t frqcr;

u16

Please don't mix uint<n>_t and u<n> in the same driver.

> +static int pll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
> +{
> +       struct cpg_priv *cpg = to_priv(hw);
> +
> +       get_round_rate(cpg, &req->rate, NULL, req->rate, req->best_parent_rate);
> +       return 0;
> +}
> +
> +static int pll_set_rate(struct clk_hw *hw,
> +                       unsigned long rate, unsigned long prate)
> +{
> +       struct cpg_priv *cpg = to_priv(hw);
> +       bool oldpll, newpll;
> +       uint16_t frqcr;

u16


> +static void __init register_div(struct device_node *node, struct cpg_priv *cpg)
> +{
> +       static const char * const divout[] = {
> +               [SH7750_CPG_FCK] = "fck",
> +               [SH7750_CPG_BCK] = "bck",
> +               [SH7750_CPG_ICK] = "ick",
> +       };
> +       struct clk *clk;
> +       int i;

unsigned int

> +
> +       for (i = 0; i < ARRAY_SIZE(divout); i++) {
> +               if (sh_div_clk_register(node, divout[i], PLLOUT,
> +                                       cpg->frqcr, i * 3, 3,
> +                                       (i == 0) ? pdiv_table : div_table,
> +                                       &clklock) < 0)
> +                       pr_err("%s: failed to register %s div clock (%ld)\n",
> +                              __func__, divout[i], PTR_ERR(clk));
> +       }
> +}
> +
> +
> +static void __init sh7750_cpg_setup(struct device_node *node)
> +{
> +       unsigned int num_parents;
> +       struct cpg_priv *cpg;
> +
> +       num_parents = of_clk_get_parent_count(node);
> +       if (num_parents < 1) {
> +               pr_err("%s: no parent found", node->name);
> +               return;
> +       }
> +
> +       cpg = kzalloc(sizeof(struct cpg_priv), GFP_KERNEL);
> +       if (!cpg) {
> +               pr_err("%s: failed to alloc memory", node->name);
> +               return;
> +       }
> +
> +       of_property_read_u32_index(node, "renesas,mode", 0, &cpg->mode);
> +       if (cpg->mode >= 7) {
> +               pr_err("%s: Invalid clock mode setting (%u)\n",
> +                      node->name, cpg->mode);
> +               goto cpg_free;
> +       }
> +       cpg->have_div1 = (of_device_is_compatible(node, "renesas,sh7750r-pll-clk") == 0);

What is this for? There are no users of "renesas,sh7750r-pll-clk".

> +
> +       cpg->frqcr = of_iomap(node, 0);
> +       if (cpg->frqcr == NULL) {
> +               pr_err("%s: failed to map divide register", node->name);
> +               goto cpg_free;
> +       }
> +
> +       cpg->wdt = of_iomap(node, 1);
> +       if (cpg->wdt == NULL) {
> +               pr_err("%s: failed to map watchdog register", node->name);
> +               goto unmap_frqcr;
> +       }
> +
> +       if (!register_pll(node, cpg))
> +               goto unmap_wdt;
> +
> +       register_div(node, cpg);
> +
> +unmap_wdt:
> +       iounmap(cpg->wdt);
> +unmap_frqcr:
> +       iounmap(cpg->frqcr);
> +cpg_free:
> +       kfree(cpg);
> +}
> +
> +CLK_OF_DECLARE(sh7750_cpg, "renesas,sh7750-cpg",
> +              sh7750_cpg_setup);

Probably you want a second entry for "renesas,sh7751-cpg"?

Is there a good reason to use CLK_OF_DECLARE()?
Perhaps because you need it early for the timer?

Most modern clock drivers use a platform_driver, registered from
e.g. subsys_initcall().  When you need an early initialization phase,
you can use CLK_OF_DECLARE_DRIVER() for the early part.

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.