[PATCH v4 2/2] pinctrl: Add driver for Sunplus SP7021

Andy Shevchenko andy.shevchenko at gmail.com
Wed Dec 15 04:03:12 PST 2021


On Wed, Dec 15, 2021 at 11:40 AM Wells Lu 呂芳騰 <wells.lu at sunplus.com> wrote:

...

> > > +/* SP7021 Pin Controller Driver.
> > > + * Copyright (C) Sunplus Tech/Tibbo Tech.
> > > + */
> >
> > This is wrong style for multi-line comments. Fix it everywhere accordingly.
>
> I'll modify all multi-line comments, for example, as shown below:
>
> /*
>  * SP7021 Pin Controller Driver.
>  * Copyright (C) Sunplus Tech/Tibbo Tech.
>  */
>
> Now, I realized that each subsystem has its own comment style.

Actually there are only two styles:
 - this one (as updated version) for entire kernel with the exception of
 - net / network one (as you used originally)

> > ...
> >
> > > +#include <linux/platform_device.h>
> > > +#include <linux/pinctrl/pinmux.h>
> > > +#include <linux/gpio/driver.h>
> > > +#include <linux/module.h>
> > > +#include <linux/bitfield.h>
> >
> > Keep them in order. Besides that it seems missed a few headers, such as of.h.
>
> I am not sure what order should I keep for inclusions.
> Reversed x'mas tree order? Alphabetic order?

Alphabetical. When you don't see a direct answer the rule of thumb is
to go to the recent contributions and check a few new drivers to see
how they are doing.

> Some reviewers ask to remove unnecessary header files.

So that reviewers are right and maybe wrong (see below for the
details), I don't see those reviews so I can't judge.

> So I removed all unnecessary header files if compilation
> completes without any errors or warnings.

Have you checked how deep and sudden the header inclusion went?

> I suppose <linux/of.h> has included by other inclusion.

Of course and it's wrong in your case. No header from above guarantees
that. See below.

> Need I add <linux/of.h> or other inclusions back?

The rule of thumb is that you have to include all headers you are a
direct user of.
There are some that guarantee inclusion of others, like
bits.h is always included if you use bitmap.h  (via bitops.h) or
compiler_attributes.h is always provided by types.h.

You have to find a golden ratio here (yes, it's kinda knowledge that
doesn't come at once, needs to have some experience).

...

> > > +       val = (reg & BIT(bit_off)) ? 1 : 0;
> >
> > !!(...) may also work, but it's rather style preference.
>
> The return value is integer 0 or 1, not Boolean.

Yes, and it's exactly what has been suggested. It's a C standard
allowed trick. With the -O2 compiler gives you the same code for both
(at least on x86).

...

> > > +       reg = readl(spp_gchip->gpioxt_base + SPPCTL_GPIO_OFF_MASTER +
> > > + reg_off);
> >
> > I noticed a potentially big issue with this driver. Are you sure it's brave enough to do
> > I/O without any synchronisation? Did I miss a lock?
>
> Do I need to add spin_lock() for all gpio operation functions?
> Please teach me what operation functions I need to add lock or
> all operation functions need lock?

I don't know. You need to answer this question, it's your code. And
you know how it's supposed to be used etc, etc.

...

> > > +       reg = readl(spp_gchip->gpioxt2_base + SPPCTL_GPIO_OFF_OD +
> > > + reg_off);
> >
> > You may create an I/O wrappers to achieve a much better to read code (no repetition of
> > this arithmetics, etc).
>
> I think this is the simplest in-line form:

No, it's harder to read and easy to mistake what the base and / or
offset is used, what value, etc.

> "spp_gchip->gpioxt2_base" is base address.
> SPPCTL_GPIO_OFF_OD is register offset to base of OD (open-drain) registers.
> reg_off is register offset to an OD register (SP7021 has 7 OD registers totally).
>
> Need I add macros (wrappers) for accessing registers?
>
> For example,
>
> #define SPPCTL_GPIO_OD(off)     (spp_gchip->gpioxt2_base + SPPCTL_GPIO_OFF_OD + off)
>
> reg = readl(SPPCTL_GPIO_OD(reg_off));
>
> or
>
> writel(reg, SPPCTL_GPIO_OD(reg_off));
>
>
> Mr. Linus Walleij told me that he likes in-line (direct) form, instead of macro
> because in-line form has better readability (No need to jump to other file for
> reading macros).
>
> Could you please share me with your idea?

It's an idea that is used in zillions of the drivers (and not via macros).

static inline spp_readl(struct ... *spp, u32 offset)
{
  return readl(...);
}

Same for _writel() and so on.

...

> > Perhaps to show only requested ones? In such case you may use
> > for_each_requested_gpio() macro.
>
> I'd like to keep showing status of all GPIOs.
> This helps us know status of all GPIOs when debugging hardware issue.

Since it's a pin control driver, the pin control debug callback can
show this. For GPIO I would rather not be bothered with not requested
pins. But it's your decision.

...

> > > +       gchip->parent =            &pdev->dev;
> >
> > > +       gchip->of_node =           pdev->dev.of_node;
> >
> > Drop this dup. GPIO library already does it for you.
>
> But when I removed the two statements, I found both 'gchip->parent' and
> 'gchip->of_node' are always 0. No one helps set it.
>
> Do I miss doing somethings?

Yes, I put blank lines around the dup and left context (as a first
line) to show why the second one is a dup. When you miss something,
read the implementation code. It's open source at the end!

...

> > > +       dev_dbg(pctldev->dev, "%s(%d, %ld, %d)\n", __func__, pin,
> > > + *configs, num_configs);
> >
> > Noise. Better to consider to add necessary tracepoints to pin control core.
>
> What should I do?
> Should I remove it?

I wouldn't expect these to be in the production-ready driver. And
since you are committing to drivers/pinctrl and not to drivers/staging
I consider that you are trying to push this code as production-ready.

...

> > > +       dev_dbg(pctldev->dev, "%s(%d)\n", __func__, offset);
> >
> > Noise. And so on, so on...
>
> Should I remove dev_dbg? Or modify it?
> But it will not print out anything in normal run, only for debugging.

See above.

...

> > > +       dev_dbg(pctldev->dev, "%s(%d), f_idx: %d, g_idx: %d, freg: %d\n",
> > > +               __func__, selector, g2fpm.f_idx, g2fpm.g_idx,
> > > + f->freg);
> >
> > No need to use __func__, and especially in case of _dbg / _debug. It can be enabled at
> > run-time with help of Dynamic Debug.
>
> Should I need to remove all __func__ in this driver?

As the first step, the second one is to remove 90%+ of these messages
as I explained above.

...

> > Looking into this rather quite big function why you can't use what pin control core provides?
>
> No, we cannot use functions pin-control core provides.
> Please refer to dt-bindings document, "pinctrl/sunplus,sp7021-pinctrl.yaml".
> We have more explanation there.

Fine, can you reuse some library functions, etc? Please, consider
refactoring to make it more readable.

...

> > > +       sppctl->groups_name = devm_kzalloc(&pdev->dev, sppctl_list_funcs_sz *
> > > +                                          SPPCTL_MAX_GROUPS *
> > > + sizeof(char *), GFP_KERNEL);
> >
> > Ditto. And check some interesting macros in overflow.h.
>
> I'll modify code to use devm_kcalloc().
>
> I'll modify sizeof() to use type of variable, that is:
>         sizeof(*sppctl->groups_name)
>
> Please teach me what macros should I check?
> There are many macros in overflow.h.

Do your homework, it's not me who makes this contribution :-)
Hint: something about multiplication.

...

> > > +       if (IS_ERR(sppctl->moon2_base)) {
> > > +               ret = PTR_ERR(sppctl->moon2_base);
> > > +               goto ioremap_failed;
> >
> > What is this for? Use return dev_err_probe() directly.
>
> There are 5 devm_ioremap_resource() in this function.
> To avoid from duplication, goto an error-handling when ioremap failed.

What error handling? You have the same point which does the same for
them, I don't see duplication avoidance. See below as well.

> > > +       }

...

> > > +ioremap_failed:
> > > +       dev_err_probe(&pdev->dev, ret, "ioremap failed!\n");
> >
> > This doesn't bring any value,
>> besides the fact that API you have used already prints a
> > message.

(1)

> I'll modify code to as shown below (error-handling here):
>
> ioremap_failed:
>         return dev_err_probe(&pdev->dev, ret, "ioremap failed!\n");
> }
>
> Is this ok?

No.

> If not, please teach me how to modify.

Read again what I wrote in (1).

> > > +       pdev->dev.platform_data = sppctl;
> >
> > Don't we have special setter for this field?
>
> I know platform_set_drvdata() function is used to set "dev->driver_data".
> I cannot find a function to set "dev->platform_data".
> Please teach me what function should I use to set "dev->platform_data"?

Ah, now I even may say that the above assignment is simply wrong.
It's not designed for what you think it's for. Use different ways.

...

> > > +       dev_info(&pdev->dev, "SP7021 PinCtrl by Sunplus/Tibbo Tech.
> > > + (c)");
> >
> > No value.
>
> This shows that pinctrl driver has probed successfully.
> Many drivers show this kind of information.

And there is no value in this information.

> Do I need to remove it? Or change to dev_dbg(...).

Neither in this case.

Explain the point "why?". In general you have to explain each line of
your code "why are you doing this or that?".

...

> > > +#ifndef __SPPCTL_H__
> > > +#define __SPPCTL_H__
> >
> > This header misses the inclusions such as bits.h.
> > And I believe more than that.
>
> Some reviewers ask to remove unnecessary header files.

What do you mean by this in this case. This is a clear miss of bits.h
here as you use macros from it. Imagine if you include this file
somewhere where bits.h hasn't found its mysterious ways.

> I removed all unnecessary header files if compilation completes
> without any errors or warnings.
>
> If compilation has done successfully,

So what? It doesn't mean the code is bad in one way or another, :-)

> does it mean all
> necessary inclusions has included well?

> Besides, before private header files are included,
> Linux or system header files will be included.
> No need extra inclusion here, right?

See above.

...

> > > +/* FIRST register:
> > > + *   0: MUX
> > > + *   1: GPIO/IOP
> > > + *   2: No change
> > > + */
> >
> > For all comments starting from here and for similar cases elsewhere:
> >  - why it is not in kernel doc?
> >  - what the value that add?
> > (Some of them so cryptic or so obvious)
>
> The comment explains usage of 'enum mux_f_mg'
> The 'enum' is only used in the driver.
> It helps programmers to remember or look-up the define of the enum.
> Need we add this kind of comment to kernel doc?

Why not?

> > > +static const struct sppctl_grp sp7021grps_spif[] = {
> > > +       EGRP("SPI_FLASH1", 1, pins_spif1),
> > > +       EGRP("SPI_FLASH2", 2, pins_spif2)
> >
> > Here and everywhere else, leave a comma if it's not a terminator entry.
>
> The constant array 'sp7021grps_spif[]' is declared and initialized
> to have 2 elements. 'EGRP("SPI_FLASH2", 2, pins_spif2)' is the
> latest element.
> Why do we need to add 'comma' for the latest element of an array?

To avoid the churn in the future when it will be expanded. Believe I
saw this kind of "proves" that this or that won't ever be expanded and
then... you may picture what happens.

> If we add extra comma, the array will have one more element.

Yes, with touching the "last" one here. Please, add commas where it's
not a crystal clear a termination (which is not in many cases, usually
arrays with NULL entry or enums with MAX value at the end).

-- 
With Best Regards,
Andy Shevchenko



More information about the linux-arm-kernel mailing list