All of lore.kernel.org
 help / color / mirror / Atom feed
From: Lars Povlsen <lars.povlsen@microchip.com>
To: Stephen Boyd <sboyd@kernel.org>
Cc: Arnd Bergmann <arnd@arndb.de>,
	Linus Walleij <linus.walleij@linaro.org>,
	SoC Team <soc@kernel.org>,
	Lars Povlsen <lars.povlsen@microchip.com>,
	"Steen Hegelund" <Steen.Hegelund@microchip.com>,
	Microchip Linux Driver Support <UNGLinuxDriver@microchip.com>,
	Olof Johansson <olof@lixom.net>,
	"Michael Turquette" <mturquette@baylibre.com>,
	<devicetree@vger.kernel.org>, <linux-clk@vger.kernel.org>,
	<linux-gpio@vger.kernel.org>,
	<linux-arm-kernel@lists.infradead.org>,
	<linux-kernel@vger.kernel.org>,
	Alexandre Belloni <alexandre.belloni@bootlin.com>
Subject: Re: [PATCH 12/14] clk: sparx5: Add Sparx5 SoC DPLL clock driver
Date: Wed, 27 May 2020 16:29:17 +0200	[thread overview]
Message-ID: <87mu5tpi2q.fsf@soft-dev15.microsemi.net> (raw)
In-Reply-To: <159054818459.88029.10644772284176356883@swboyd.mtv.corp.google.com>


Stephen Boyd writes:

> Quoting Lars Povlsen (2020-05-13 05:55:30)
>> diff --git a/drivers/clk/clk-sparx5.c b/drivers/clk/clk-sparx5.c
>> new file mode 100644
>> index 0000000000000..685b3028a7071
>> --- /dev/null
>> +++ b/drivers/clk/clk-sparx5.c
>> @@ -0,0 +1,269 @@
>> +// SPDX-License-Identifier: GPL-2.0-or-later
>> +/*
>> + * Microchip Sparx5 SoC Clock driver.
>> + *
>> + * Copyright (c) 2019 Microchip Inc.
>> + *
>> + * Author: Lars Povlsen <lars.povlsen@microchip.com>
>> + */
>> +
>> +#include <linux/io.h>
>> +#include <linux/clk-provider.h>
>> +#include <linux/of.h>
>> +#include <linux/of_address.h>
>> +#include <linux/slab.h>
>> +#include <linux/platform_device.h>
>> +#include <dt-bindings/clock/microchip,sparx5.h>
>> +
>> +#define PLL_DIV_MASK           GENMASK(7, 0)
>> +#define PLL_PRE_DIV_MASK       GENMASK(10, 8)
>> +#define PLL_PRE_DIV_SHIFT      8
>> +#define PLL_ROT_DIR            BIT(11)
>> +#define PLL_ROT_SEL_MASK       GENMASK(13, 12)
>> +#define PLL_ROT_SEL_SHIFT      12
>> +#define PLL_ROT_ENA            BIT(14)
>> +#define PLL_CLK_ENA            BIT(15)
>> +
>> +#define MAX_SEL 4
>> +#define MAX_PRE BIT(3)
>> +
>> +#define KHZ 1000
>> +#define MHZ (KHZ*KHZ)
>
> I suspect (1000 * KHZ) would make more sense.
>

Fine.

>> +
>> +#define BASE_CLOCK (2500UL*MHZ)
>> +
>> +static u8 sel_rates[MAX_SEL] = { 0, 2*8, 2*4, 2*2 };
>
> const?
>

Yes, sure.

>> +
>> +static const char *clk_names[N_CLOCKS] = {
>> +       "core", "ddr", "cpu2", "arm2",
>> +       "aux1", "aux2", "aux3", "aux4",
>> +       "synce",
>> +};
>> +
>> +struct s5_hw_clk {
>> +       struct clk_hw hw;
>> +       void __iomem *reg;
>> +       int index;
>> +};
>> +
>> +struct s5_clk_data {
>> +       void __iomem *base;
>> +       struct s5_hw_clk s5_hw[N_CLOCKS];
>> +};
>> +
>> +struct pll_conf {
>> +       int freq;
>> +       u8 div;
>> +       bool rot_ena;
>> +       u8 rot_sel;
>> +       u8 rot_dir;
>> +       u8 pre_div;
>> +};
>> +
>> +#define to_clk_pll(hw) container_of(hw, struct s5_hw_clk, hw)
>> +
>> +unsigned long calc_freq(const struct pll_conf *pdata)
>> +{
>> +       unsigned long rate = BASE_CLOCK / pdata->div;
>> +
>> +       if (pdata->rot_ena) {
>> +               unsigned long base = BASE_CLOCK / pdata->div;
>> +               int sign = pdata->rot_dir ? -1 : 1;
>> +               int divt = sel_rates[pdata->rot_sel] * (1 + pdata->pre_div);
>> +               int divb = divt + sign;
>> +
>> +               rate = mult_frac(base, divt, divb);
>> +               rate = roundup(rate, 1000);
>> +       }
>> +
>> +       return rate;
>> +}
>> +
>> +static unsigned long clk_calc_params(unsigned long rate,
>> +                                    struct pll_conf *conf)
>> +{
>> +       memset(conf, 0, sizeof(*conf));
>> +
>> +       conf->div = DIV_ROUND_CLOSEST_ULL(BASE_CLOCK, rate);
>> +
>> +       if (BASE_CLOCK % rate) {
>> +               struct pll_conf best;
>> +               ulong cur_offset, best_offset = rate;
>> +               int i, j;
>> +
>> +               /* Enable fractional rotation */
>> +               conf->rot_ena = true;
>> +
>> +               if ((BASE_CLOCK / rate) != conf->div) {
>> +                       /* Overshoot, adjust other direction */
>> +                       conf->rot_dir = 1;
>> +               }
>> +
>> +               /* Brute force search over MAX_PRE * (MAX_SEL - 1) = 24 */
>> +               for (i = 0; i < MAX_PRE; i++) {
>> +                       conf->pre_div = i;
>> +                       for (j = 1; j < MAX_SEL; j++) {
>> +                               conf->rot_sel = j;
>> +                               conf->freq = calc_freq(conf);
>> +                               cur_offset = abs(rate - conf->freq);
>> +                               if (cur_offset == 0)
>> +                                       /* Perfect fit */
>> +                                       goto done;
>
> Why not 'break' and drop the label?
>

Its a dual loop. Anyway, I changed it to add "best_offset > 0" in the
loop guards and drop "cur_offset == 0" as a special case, so no goto.

>> +                               if (cur_offset < best_offset) {
>> +                                       /* Better fit found */
>> +                                       best_offset = cur_offset;
>> +                                       best = *conf;
>> +                               }
>> +                       }
>> +               }
>> +               /* Best match */
>> +               *conf = best;
>> +       }
>> +
>> +done:
>> +       return conf->freq;
>> +}
>> +
>> +static int clk_pll_enable(struct clk_hw *hw)
>> +{
>> +       struct s5_hw_clk *pll = to_clk_pll(hw);
>> +       u32 val = readl(pll->reg);
>> +
>> +       val |= PLL_CLK_ENA;
>> +       writel(val, pll->reg);
>> +       pr_debug("%s: Enable val %04x\n", clk_names[pll->index], val);
>> +       return 0;
>> +}
>> +
>> +static void clk_pll_disable(struct clk_hw *hw)
>> +{
>> +       struct s5_hw_clk *pll = to_clk_pll(hw);
>> +       u32 val = readl(pll->reg);
>> +
>> +       val &= ~PLL_CLK_ENA;
>> +       writel(val, pll->reg);
>> +       pr_debug("%s: Disable val %04x\n", clk_names[pll->index], val);
>
> Can we drop these pr_debug() prints? They're probably never going to be
> used after developing this driver.
>
>> +}
>> +
>> +static int clk_pll_set_rate(struct clk_hw *hw,
>
> Please rename clk_pll to something less generic, like s5_pll or
> something.
>

Yeah, I see that. I changed all generic symbols to use s5_ prefix where
applicable. Also fixed non-static calc_freq() symbol.

>> +                           unsigned long rate,
>> +                           unsigned long parent_rate)
>> +{
>> +       struct s5_hw_clk *pll = to_clk_pll(hw);
>> +       struct pll_conf conf;
>> +       unsigned long eff_rate;
>> +       int ret = 0;
>> +
>> +       eff_rate = clk_calc_params(rate, &conf);
>> +       if (eff_rate == rate) {
>> +               u32 val;
>> +
>> +               val = readl(pll->reg) & PLL_CLK_ENA;
>> +               val |= PLL_DIV_MASK & conf.div;
>> +               if (conf.rot_ena) {
>> +                       val |= (PLL_ROT_ENA |
>> +                               (PLL_ROT_SEL_MASK &
>> +                                (conf.rot_sel << PLL_ROT_SEL_SHIFT)) |
>> +                               (PLL_PRE_DIV_MASK &
>> +                                (conf.pre_div << PLL_PRE_DIV_SHIFT)));
>
> This can use the FIELD_GET and helpers?
>

Yes, makes sense. Done.

>> +                       if (conf.rot_dir)
>> +                               val |= PLL_ROT_DIR;
>> +               }
>> +               pr_debug("%s: Rate %ld >= 0x%04x\n",
>> +                        clk_names[pll->index], rate, val);
>> +               writel(val, pll->reg);
>> +       } else {
>> +               pr_err("%s: freq unsupported: %ld paren %ld\n",
>> +                      clk_names[pll->index], rate, parent_rate);
>> +               ret = -ENOTSUPP;
>
> I'd prefer we short circuit the function
>
>         eff_rate = clk_calc_params(...);
>         if (eff_rate != rate)
>                 return -ENOTSUPP;
>
>         do the other things...
>
> This avoids lots of indentation.

Ok, noted.

>
>> +       }
>> +
>> +       return ret;
>> +}
>> +
>> +static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
>> +                                        unsigned long parent_rate)
>> +{
>> +       /* Don't care */
>
> What does this mean? recalc_rate is supposed to tell us what rate has
> been achieved for this clk.

I added a proper implementation for this.

>
>> +       return 0;
>> +}
>> +
>> +static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
>> +                              unsigned long *parent_rate)
>> +{
>> +       struct pll_conf conf;
>> +       unsigned long eff_rate;
>> +
>> +       eff_rate = clk_calc_params(rate, &conf);
>> +       pr_debug("%s: Rate %ld rounded to %ld\n", __func__, rate, eff_rate);
>> +
>> +       return eff_rate;
>> +}
>> +
>> +static const struct clk_ops s5_pll_ops = {
>> +       .enable         = clk_pll_enable,
>> +       .disable        = clk_pll_disable,
>> +       .set_rate       = clk_pll_set_rate,
>> +       .round_rate     = clk_pll_round_rate,
>> +       .recalc_rate    = clk_pll_recalc_rate,
>> +};
>> +
>> +static struct s5_clk_data *s5_clk_alloc(struct device_node *np)
>> +{
>> +       struct s5_clk_data *clk_data;
>> +
>> +       clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
>> +       if (WARN_ON(!clk_data))
>
> Drop the WARN_ON(), kzalloc() already prints a big stacktrace when it
> fails.

Yes.

>
>> +               return NULL;
>> +
>> +       clk_data->base = of_iomap(np, 0);
>> +       if (WARN_ON(!clk_data->base))
>> +               return NULL;
>> +
>> +       return clk_data;
>
> Just inline this function at the callsite please.
>

Yes.

>> +}
>> +
>> +static struct clk_hw *s5_clk_hw_get(struct of_phandle_args *clkspec, void *data)
>> +{
>> +       struct s5_clk_data *pll_clk = data;
>> +       unsigned int idx = clkspec->args[0];
>> +
>> +       if (idx >= N_CLOCKS) {
>> +               pr_err("%s: invalid index %u\n", __func__, idx);
>> +               return ERR_PTR(-EINVAL);
>> +       }
>> +
>> +       return &pll_clk->s5_hw[idx].hw;
>> +}
>> +
>> +static void __init s5_pll_init(struct device_node *np)
>> +{
>> +       int i, ret;
>> +       struct s5_clk_data *pll_clk;
>> +       struct clk_init_data init = { 0 };
>
> Just do init = { } so that 0 doesn't trip up sparse.

I'm not sure what you mean by "trip up sparse", but its changed now.

>
>> +
>> +       pll_clk = s5_clk_alloc(np);
>> +       if (!pll_clk)
>> +               return;
>> +
>> +       init.ops = &s5_pll_ops;
>> +       init.parent_names = NULL;
>> +       init.num_parents = 0;
>
> Drop these last two lines if there aren't any parents.
>

OK.

>> +
>> +       for (i = 0; i < N_CLOCKS; i++) {
>> +               struct s5_hw_clk *s5_hw = &pll_clk->s5_hw[i];
>> +
>> +               init.name = clk_names[i];
>> +               s5_hw->index = i;
>> +               s5_hw->reg = pll_clk->base + (i * sizeof(u32));
>> +               s5_hw->hw.init = &init;
>> +               ret = of_clk_hw_register(np, &s5_hw->hw);
>> +               if (ret) {
>> +                       pr_err("failed to register %s clock\n", init.name);
>> +                       return;
>> +               }
>> +       }
>> +
>> +       of_clk_add_hw_provider(np, s5_clk_hw_get, pll_clk);
>> +}
>> +CLK_OF_DECLARE_DRIVER(microchip_s5, "microchip,sparx5-dpll", s5_pll_init);
>
> Why DECLARE_DRIVER? Please add a comment indicating the other driver
> that is supposed to probe against this node. And is there any reason
> this can't be a platform driver? That is preferred over
> CLK_OF_DECLARE*() usage.

I will change it to a platform driver.

Thank you very much for your comments, they are highly appreciated.

---Lars

--
Lars Povlsen,
Microchip

WARNING: multiple messages have this Message-ID (diff)
From: Lars Povlsen <lars.povlsen@microchip.com>
To: Stephen Boyd <sboyd@kernel.org>
Cc: devicetree@vger.kernel.org,
	Alexandre Belloni <alexandre.belloni@bootlin.com>,
	Arnd Bergmann <arnd@arndb.de>,
	linux-gpio@vger.kernel.org,
	Linus Walleij <linus.walleij@linaro.org>,
	linux-clk@vger.kernel.org, linux-kernel@vger.kernel.org,
	Microchip Linux Driver Support <UNGLinuxDriver@microchip.com>,
	Michael Turquette <mturquette@baylibre.com>,
	SoC Team <soc@kernel.org>,
	linux-arm-kernel@lists.infradead.org,
	Olof Johansson <olof@lixom.net>,
	Steen Hegelund <Steen.Hegelund@microchip.com>,
	Lars Povlsen <lars.povlsen@microchip.com>
Subject: Re: [PATCH 12/14] clk: sparx5: Add Sparx5 SoC DPLL clock driver
Date: Wed, 27 May 2020 16:29:17 +0200	[thread overview]
Message-ID: <87mu5tpi2q.fsf@soft-dev15.microsemi.net> (raw)
In-Reply-To: <159054818459.88029.10644772284176356883@swboyd.mtv.corp.google.com>


Stephen Boyd writes:

> Quoting Lars Povlsen (2020-05-13 05:55:30)
>> diff --git a/drivers/clk/clk-sparx5.c b/drivers/clk/clk-sparx5.c
>> new file mode 100644
>> index 0000000000000..685b3028a7071
>> --- /dev/null
>> +++ b/drivers/clk/clk-sparx5.c
>> @@ -0,0 +1,269 @@
>> +// SPDX-License-Identifier: GPL-2.0-or-later
>> +/*
>> + * Microchip Sparx5 SoC Clock driver.
>> + *
>> + * Copyright (c) 2019 Microchip Inc.
>> + *
>> + * Author: Lars Povlsen <lars.povlsen@microchip.com>
>> + */
>> +
>> +#include <linux/io.h>
>> +#include <linux/clk-provider.h>
>> +#include <linux/of.h>
>> +#include <linux/of_address.h>
>> +#include <linux/slab.h>
>> +#include <linux/platform_device.h>
>> +#include <dt-bindings/clock/microchip,sparx5.h>
>> +
>> +#define PLL_DIV_MASK           GENMASK(7, 0)
>> +#define PLL_PRE_DIV_MASK       GENMASK(10, 8)
>> +#define PLL_PRE_DIV_SHIFT      8
>> +#define PLL_ROT_DIR            BIT(11)
>> +#define PLL_ROT_SEL_MASK       GENMASK(13, 12)
>> +#define PLL_ROT_SEL_SHIFT      12
>> +#define PLL_ROT_ENA            BIT(14)
>> +#define PLL_CLK_ENA            BIT(15)
>> +
>> +#define MAX_SEL 4
>> +#define MAX_PRE BIT(3)
>> +
>> +#define KHZ 1000
>> +#define MHZ (KHZ*KHZ)
>
> I suspect (1000 * KHZ) would make more sense.
>

Fine.

>> +
>> +#define BASE_CLOCK (2500UL*MHZ)
>> +
>> +static u8 sel_rates[MAX_SEL] = { 0, 2*8, 2*4, 2*2 };
>
> const?
>

Yes, sure.

>> +
>> +static const char *clk_names[N_CLOCKS] = {
>> +       "core", "ddr", "cpu2", "arm2",
>> +       "aux1", "aux2", "aux3", "aux4",
>> +       "synce",
>> +};
>> +
>> +struct s5_hw_clk {
>> +       struct clk_hw hw;
>> +       void __iomem *reg;
>> +       int index;
>> +};
>> +
>> +struct s5_clk_data {
>> +       void __iomem *base;
>> +       struct s5_hw_clk s5_hw[N_CLOCKS];
>> +};
>> +
>> +struct pll_conf {
>> +       int freq;
>> +       u8 div;
>> +       bool rot_ena;
>> +       u8 rot_sel;
>> +       u8 rot_dir;
>> +       u8 pre_div;
>> +};
>> +
>> +#define to_clk_pll(hw) container_of(hw, struct s5_hw_clk, hw)
>> +
>> +unsigned long calc_freq(const struct pll_conf *pdata)
>> +{
>> +       unsigned long rate = BASE_CLOCK / pdata->div;
>> +
>> +       if (pdata->rot_ena) {
>> +               unsigned long base = BASE_CLOCK / pdata->div;
>> +               int sign = pdata->rot_dir ? -1 : 1;
>> +               int divt = sel_rates[pdata->rot_sel] * (1 + pdata->pre_div);
>> +               int divb = divt + sign;
>> +
>> +               rate = mult_frac(base, divt, divb);
>> +               rate = roundup(rate, 1000);
>> +       }
>> +
>> +       return rate;
>> +}
>> +
>> +static unsigned long clk_calc_params(unsigned long rate,
>> +                                    struct pll_conf *conf)
>> +{
>> +       memset(conf, 0, sizeof(*conf));
>> +
>> +       conf->div = DIV_ROUND_CLOSEST_ULL(BASE_CLOCK, rate);
>> +
>> +       if (BASE_CLOCK % rate) {
>> +               struct pll_conf best;
>> +               ulong cur_offset, best_offset = rate;
>> +               int i, j;
>> +
>> +               /* Enable fractional rotation */
>> +               conf->rot_ena = true;
>> +
>> +               if ((BASE_CLOCK / rate) != conf->div) {
>> +                       /* Overshoot, adjust other direction */
>> +                       conf->rot_dir = 1;
>> +               }
>> +
>> +               /* Brute force search over MAX_PRE * (MAX_SEL - 1) = 24 */
>> +               for (i = 0; i < MAX_PRE; i++) {
>> +                       conf->pre_div = i;
>> +                       for (j = 1; j < MAX_SEL; j++) {
>> +                               conf->rot_sel = j;
>> +                               conf->freq = calc_freq(conf);
>> +                               cur_offset = abs(rate - conf->freq);
>> +                               if (cur_offset == 0)
>> +                                       /* Perfect fit */
>> +                                       goto done;
>
> Why not 'break' and drop the label?
>

Its a dual loop. Anyway, I changed it to add "best_offset > 0" in the
loop guards and drop "cur_offset == 0" as a special case, so no goto.

>> +                               if (cur_offset < best_offset) {
>> +                                       /* Better fit found */
>> +                                       best_offset = cur_offset;
>> +                                       best = *conf;
>> +                               }
>> +                       }
>> +               }
>> +               /* Best match */
>> +               *conf = best;
>> +       }
>> +
>> +done:
>> +       return conf->freq;
>> +}
>> +
>> +static int clk_pll_enable(struct clk_hw *hw)
>> +{
>> +       struct s5_hw_clk *pll = to_clk_pll(hw);
>> +       u32 val = readl(pll->reg);
>> +
>> +       val |= PLL_CLK_ENA;
>> +       writel(val, pll->reg);
>> +       pr_debug("%s: Enable val %04x\n", clk_names[pll->index], val);
>> +       return 0;
>> +}
>> +
>> +static void clk_pll_disable(struct clk_hw *hw)
>> +{
>> +       struct s5_hw_clk *pll = to_clk_pll(hw);
>> +       u32 val = readl(pll->reg);
>> +
>> +       val &= ~PLL_CLK_ENA;
>> +       writel(val, pll->reg);
>> +       pr_debug("%s: Disable val %04x\n", clk_names[pll->index], val);
>
> Can we drop these pr_debug() prints? They're probably never going to be
> used after developing this driver.
>
>> +}
>> +
>> +static int clk_pll_set_rate(struct clk_hw *hw,
>
> Please rename clk_pll to something less generic, like s5_pll or
> something.
>

Yeah, I see that. I changed all generic symbols to use s5_ prefix where
applicable. Also fixed non-static calc_freq() symbol.

>> +                           unsigned long rate,
>> +                           unsigned long parent_rate)
>> +{
>> +       struct s5_hw_clk *pll = to_clk_pll(hw);
>> +       struct pll_conf conf;
>> +       unsigned long eff_rate;
>> +       int ret = 0;
>> +
>> +       eff_rate = clk_calc_params(rate, &conf);
>> +       if (eff_rate == rate) {
>> +               u32 val;
>> +
>> +               val = readl(pll->reg) & PLL_CLK_ENA;
>> +               val |= PLL_DIV_MASK & conf.div;
>> +               if (conf.rot_ena) {
>> +                       val |= (PLL_ROT_ENA |
>> +                               (PLL_ROT_SEL_MASK &
>> +                                (conf.rot_sel << PLL_ROT_SEL_SHIFT)) |
>> +                               (PLL_PRE_DIV_MASK &
>> +                                (conf.pre_div << PLL_PRE_DIV_SHIFT)));
>
> This can use the FIELD_GET and helpers?
>

Yes, makes sense. Done.

>> +                       if (conf.rot_dir)
>> +                               val |= PLL_ROT_DIR;
>> +               }
>> +               pr_debug("%s: Rate %ld >= 0x%04x\n",
>> +                        clk_names[pll->index], rate, val);
>> +               writel(val, pll->reg);
>> +       } else {
>> +               pr_err("%s: freq unsupported: %ld paren %ld\n",
>> +                      clk_names[pll->index], rate, parent_rate);
>> +               ret = -ENOTSUPP;
>
> I'd prefer we short circuit the function
>
>         eff_rate = clk_calc_params(...);
>         if (eff_rate != rate)
>                 return -ENOTSUPP;
>
>         do the other things...
>
> This avoids lots of indentation.

Ok, noted.

>
>> +       }
>> +
>> +       return ret;
>> +}
>> +
>> +static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
>> +                                        unsigned long parent_rate)
>> +{
>> +       /* Don't care */
>
> What does this mean? recalc_rate is supposed to tell us what rate has
> been achieved for this clk.

I added a proper implementation for this.

>
>> +       return 0;
>> +}
>> +
>> +static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
>> +                              unsigned long *parent_rate)
>> +{
>> +       struct pll_conf conf;
>> +       unsigned long eff_rate;
>> +
>> +       eff_rate = clk_calc_params(rate, &conf);
>> +       pr_debug("%s: Rate %ld rounded to %ld\n", __func__, rate, eff_rate);
>> +
>> +       return eff_rate;
>> +}
>> +
>> +static const struct clk_ops s5_pll_ops = {
>> +       .enable         = clk_pll_enable,
>> +       .disable        = clk_pll_disable,
>> +       .set_rate       = clk_pll_set_rate,
>> +       .round_rate     = clk_pll_round_rate,
>> +       .recalc_rate    = clk_pll_recalc_rate,
>> +};
>> +
>> +static struct s5_clk_data *s5_clk_alloc(struct device_node *np)
>> +{
>> +       struct s5_clk_data *clk_data;
>> +
>> +       clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
>> +       if (WARN_ON(!clk_data))
>
> Drop the WARN_ON(), kzalloc() already prints a big stacktrace when it
> fails.

Yes.

>
>> +               return NULL;
>> +
>> +       clk_data->base = of_iomap(np, 0);
>> +       if (WARN_ON(!clk_data->base))
>> +               return NULL;
>> +
>> +       return clk_data;
>
> Just inline this function at the callsite please.
>

Yes.

>> +}
>> +
>> +static struct clk_hw *s5_clk_hw_get(struct of_phandle_args *clkspec, void *data)
>> +{
>> +       struct s5_clk_data *pll_clk = data;
>> +       unsigned int idx = clkspec->args[0];
>> +
>> +       if (idx >= N_CLOCKS) {
>> +               pr_err("%s: invalid index %u\n", __func__, idx);
>> +               return ERR_PTR(-EINVAL);
>> +       }
>> +
>> +       return &pll_clk->s5_hw[idx].hw;
>> +}
>> +
>> +static void __init s5_pll_init(struct device_node *np)
>> +{
>> +       int i, ret;
>> +       struct s5_clk_data *pll_clk;
>> +       struct clk_init_data init = { 0 };
>
> Just do init = { } so that 0 doesn't trip up sparse.

I'm not sure what you mean by "trip up sparse", but its changed now.

>
>> +
>> +       pll_clk = s5_clk_alloc(np);
>> +       if (!pll_clk)
>> +               return;
>> +
>> +       init.ops = &s5_pll_ops;
>> +       init.parent_names = NULL;
>> +       init.num_parents = 0;
>
> Drop these last two lines if there aren't any parents.
>

OK.

>> +
>> +       for (i = 0; i < N_CLOCKS; i++) {
>> +               struct s5_hw_clk *s5_hw = &pll_clk->s5_hw[i];
>> +
>> +               init.name = clk_names[i];
>> +               s5_hw->index = i;
>> +               s5_hw->reg = pll_clk->base + (i * sizeof(u32));
>> +               s5_hw->hw.init = &init;
>> +               ret = of_clk_hw_register(np, &s5_hw->hw);
>> +               if (ret) {
>> +                       pr_err("failed to register %s clock\n", init.name);
>> +                       return;
>> +               }
>> +       }
>> +
>> +       of_clk_add_hw_provider(np, s5_clk_hw_get, pll_clk);
>> +}
>> +CLK_OF_DECLARE_DRIVER(microchip_s5, "microchip,sparx5-dpll", s5_pll_init);
>
> Why DECLARE_DRIVER? Please add a comment indicating the other driver
> that is supposed to probe against this node. And is there any reason
> this can't be a platform driver? That is preferred over
> CLK_OF_DECLARE*() usage.

I will change it to a platform driver.

Thank you very much for your comments, they are highly appreciated.

---Lars

--
Lars Povlsen,
Microchip

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

  reply	other threads:[~2020-05-27 14:29 UTC|newest]

Thread overview: 71+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-05-13 12:55 [PATCH 00/14] Adding support for Microchip Sparx5 SoC Lars Povlsen
2020-05-13 12:55 ` Lars Povlsen
2020-05-13 12:55 ` [PATCH 01/14] pinctrl: ocelot: Should register GPIO's even if not irq controller Lars Povlsen
2020-05-13 12:55   ` Lars Povlsen
2020-05-18  7:29   ` Linus Walleij
2020-05-18  7:29     ` Linus Walleij
2020-05-13 12:55 ` [PATCH 02/14] pinctrl: ocelot: Remove instance number from pin functions Lars Povlsen
2020-05-13 12:55   ` Lars Povlsen
2020-05-18  7:31   ` Linus Walleij
2020-05-18  7:31     ` Linus Walleij
2020-05-13 12:55 ` [PATCH 03/14] pinctrl: ocelot: Fix GPIO interrupt decoding on Jaguar2 Lars Povlsen
2020-05-13 12:55   ` Lars Povlsen
2020-05-18  7:31   ` Linus Walleij
2020-05-18  7:31     ` Linus Walleij
2020-05-13 12:55 ` [PATCH 04/14] arm64: sparx5: Add support for Microchip 2xA53 SoC Lars Povlsen
2020-05-13 12:55   ` Lars Povlsen
2020-05-13 12:55 ` [PATCH 05/14] dt-bindings: arm: sparx5: Add documentation for Microchip Sparx5 SoC Lars Povlsen
2020-05-13 12:55   ` Lars Povlsen
2020-05-28  2:11   ` Rob Herring
2020-05-28  2:11     ` Rob Herring
2020-06-02  9:10     ` Lars Povlsen
2020-06-02  9:10       ` Lars Povlsen
2020-05-13 12:55 ` [PATCH 06/14] arm64: dts: sparx5: Add basic cpu support Lars Povlsen
2020-05-13 12:55   ` Lars Povlsen
2020-05-13 15:39   ` Marc Zyngier
2020-05-13 15:39     ` Marc Zyngier
2020-05-15 15:09     ` Lars Povlsen
2020-05-15 15:09       ` Lars Povlsen
2020-05-15 15:30       ` Robin Murphy
2020-05-15 15:30         ` Robin Murphy
2020-05-18  7:43         ` Lars Povlsen
2020-05-18  7:43           ` Lars Povlsen
2020-05-15 16:31       ` Marc Zyngier
2020-05-13 12:55 ` [PATCH 07/14] dt-bindings: pinctrl: ocelot: Add Sparx5 SoC support Lars Povlsen
2020-05-13 12:55   ` Lars Povlsen
2020-05-18  7:33   ` Linus Walleij
2020-05-18  7:33     ` Linus Walleij
2020-05-13 12:55 ` [PATCH 08/14] arm64: dts: sparx5: Add pinctrl support Lars Povlsen
2020-05-13 12:55   ` Lars Povlsen
2020-05-13 12:55 ` [PATCH 09/14] pinctrl: ocelot: Add Sparx5 SoC support Lars Povlsen
2020-05-13 12:55   ` Lars Povlsen
2020-05-14 18:09   ` kbuild test robot
2020-05-14 18:09     ` kbuild test robot
2020-05-14 18:09     ` kbuild test robot
2020-05-15 15:52     ` Lars Povlsen
2020-05-15 15:52       ` Lars Povlsen
2020-05-15 15:52       ` Lars Povlsen
2020-05-13 12:55 ` [PATCH 10/14] dt-bindings: clock: sparx5: Add Sparx5 SoC DPLL clock Lars Povlsen
2020-05-13 12:55   ` Lars Povlsen
2020-05-27  2:46   ` Stephen Boyd
2020-05-29 14:04     ` Lars Povlsen
2020-05-29 14:04       ` Lars Povlsen
2020-05-28  2:18   ` Rob Herring
2020-05-28  2:18     ` Rob Herring
2020-06-02  8:39     ` Lars Povlsen
2020-06-02  8:39       ` Lars Povlsen
2020-05-13 12:55 ` [PATCH 11/14] dt-bindings: clock: sparx5: Add bindings include file Lars Povlsen
2020-05-13 12:55   ` Lars Povlsen
2020-05-27  2:56   ` Stephen Boyd
2020-05-13 12:55 ` [PATCH 12/14] clk: sparx5: Add Sparx5 SoC DPLL clock driver Lars Povlsen
2020-05-13 12:55   ` Lars Povlsen
2020-05-27  2:56   ` Stephen Boyd
2020-05-27 14:29     ` Lars Povlsen [this message]
2020-05-27 14:29       ` Lars Povlsen
2020-05-27 19:08       ` Stephen Boyd
2020-05-13 12:55 ` [PATCH 13/14] arm64: dts: sparx5: Add Sparx5 SoC DPLL clock Lars Povlsen
2020-05-13 12:55   ` Lars Povlsen
2020-05-13 12:55 ` [PATCH 14/14] arm64: dts: sparx5: Add i2c devices, i2c muxes Lars Povlsen
2020-05-13 12:55   ` Lars Povlsen
2020-05-21 10:16 ` [PATCH 00/14] Adding support for Microchip Sparx5 SoC Arnd Bergmann
2020-05-21 10:16   ` Arnd Bergmann

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87mu5tpi2q.fsf@soft-dev15.microsemi.net \
    --to=lars.povlsen@microchip.com \
    --cc=Steen.Hegelund@microchip.com \
    --cc=UNGLinuxDriver@microchip.com \
    --cc=alexandre.belloni@bootlin.com \
    --cc=arnd@arndb.de \
    --cc=devicetree@vger.kernel.org \
    --cc=linus.walleij@linaro.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-clk@vger.kernel.org \
    --cc=linux-gpio@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mturquette@baylibre.com \
    --cc=olof@lixom.net \
    --cc=sboyd@kernel.org \
    --cc=soc@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.