All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Jonathan Neuschäfer" <j.neuschaefer@gmx.net>
To: Andy Shevchenko <andy.shevchenko@gmail.com>
Cc: "Jonathan Neuschäfer" <j.neuschaefer@gmx.net>,
	"linux-gpio@vger.kernel.org" <linux-gpio@vger.kernel.org>,
	"devicetree@vger.kernel.org" <devicetree@vger.kernel.org>,
	"Linus Walleij" <linus.walleij@linaro.org>,
	"Rob Herring" <robh+dt@kernel.org>,
	"openbmc@lists.ozlabs.org" <openbmc@lists.ozlabs.org>,
	"Tomer Maimon" <tmaimon77@gmail.com>,
	"Joel Stanley" <joel@jms.id.au>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH v2 5/8] pinctrl: nuvoton: Add driver for WPCM450
Date: Wed, 8 Dec 2021 14:58:30 +0100	[thread overview]
Message-ID: <YbC6Bv2teZ5CFhFQ@latitude> (raw)
In-Reply-To: <CAHp75Vew=M_ofNM5pmeHtTJHXRUbbO4RrtgYAtLBznTBm3CS6Q@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 7225 bytes --]

Hi,

On Wed, Dec 08, 2021 at 01:24:18PM +0200, Andy Shevchenko wrote:
> On Tuesday, December 7, 2021, Jonathan Neuschäfer <j.neuschaefer@gmx.net>
> wrote:
> 
> > This driver is based on the one for NPCM7xx, because the WPCM450 is a
> > predecessor of those SoCs. Notable differences:
> >
> > - WPCM450, the GPIO registers are not organized in multiple banks, but
> >   rather placed continually into the same register block. This affects
> >   how register offsets are computed.
> > - Pinmux nodes can explicitly select GPIO mode, whereas, in the npcm7xx
> >   driver, this happens automatically when a GPIO is requested.
> >
> > Some functionality implemented in the hardware was (for now) left unused
> > in the driver, specifically blinking and pull-up/down.
> >
> > Signed-off-by: Jonathan Neuschäfer <j.neuschaefer@gmx.net>
> > ---
[...]
> > +
> > +#include <linux/device.h>
> > +#include <linux/fwnode.h>
> > +#include <linux/gpio/driver.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/irq.h>
> > +#include <linux/mfd/syscon.h>
> > +#include <linux/module.h>
> > +#include <linux/mod_devicetable.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/regmap.h>
> 
> 
> + blank line?

Sounds reasonable, I'll add it.


> > +struct wpcm450_gpio {
> > +       struct wpcm450_pinctrl  *pctrl;
> > +       struct gpio_chip        gc;
> 
> 
> Making this first speeds up pointer arithmetics by making it no-op at
> compile time.

Will do.


> > +static int wpcm450_gpio_irq_bitnum(struct wpcm450_gpio *gpio, struct
> > irq_data *d)
> > +{
> > +       int hwirq = irqd_to_hwirq(d);
> > +
> > +       if (hwirq < gpio->first_irq_gpio)
> > +               return -EINVAL;
> > +
> > +       if (hwirq - gpio->first_irq_gpio >= gpio->num_irqs)
> > +               return -EINVAL;
> > +
> > +       return hwirq - gpio->first_irq_gpio + gpio->first_irq_bit;
> > +}
> > +
> > +static int wpcm450_irq_bitnum_to_gpio(struct wpcm450_gpio *gpio, int
> > bitnum)
> > +{
> > +       if (bitnum < gpio->first_irq_bit)
> > +               return -EINVAL;
> > +
> > +       if (bitnum - gpio->first_irq_bit > gpio->num_irqs)
> > +               return -EINVAL;
> > +
> > +       return bitnum - gpio->first_irq_bit + gpio->first_irq_gpio;
> > +}
> >
> 
> 
> Have you chance to look at bitmap_remap() and bitmap_bitremap() APIs? I’m
> pretty sure you can make this all cleaner by switching to those calls and
> represent the GPIOs as continuous bitmap on the Linux side while on the
> hardware it will be sparse. Check gpio-Xilinx for the details of use.

I haven't looked at it yet in detail, but I'll consider it for the next
iteration.

> > +static void wpcm450_gpio_fix_evpol(struct wpcm450_gpio *gpio, unsigned
> > long all)
> > +{
> 
> 
> 
> What is this quirk (?) for? Please add a comment.

The hardware does not support triggering on both edges, so the trigger
edge polarity has to be adjusted before the next interrupt can work
properly.

I'll add a comment.


> > +static void wpcm450_gpio_irqhandler(struct irq_desc *desc)
> > +{
> > +       struct wpcm450_gpio *gpio = gpiochip_get_data(irq_desc_
> > get_handler_data(desc));
> > +       struct wpcm450_pinctrl *pctrl = gpio->pctrl;
> > +       struct irq_chip *chip = irq_desc_get_chip(desc);
> > +       unsigned long pending;
> > +       unsigned long flags;
> > +       unsigned long ours;
> > +       unsigned int bit;
> > +
> > +       ours = ((1UL << gpio->num_irqs) - 1) << gpio->first_irq_bit;
> 
> 
> BIT()

I'll use it, but in this case, I think it doesn't simplify much the
whole expression all that much. Is there perhaps a macro that
constructs a continuous bitmask of N bits, perhaps additionally
left-shifted by M bits?

Maybe somewhere in the bitmap_* API...


> > +       chained_irq_enter(chip, desc);
> > +       for_each_set_bit(bit, &pending, 32) {
> > +               int offset = wpcm450_irq_bitnum_to_gpio(gpio, bit);
> > +               int irq = irq_find_mapping(gpio->gc.irq.domain, offset);
> > +
> > +               generic_handle_irq(irq);
> 
> 
> Above two are now represented by another generic IRQ handle call, check
> relatively recently updated drivers around.

Will do.

> > +       }
> > +       chained_irq_exit(chip, desc);



> > +               spin_lock_irqsave(&pctrl->lock, flags);
> > +               reg = ioread32(pctrl->gpio_base + WPCM450_GPEVDBNC);
> > +               __assign_bit(bit, &reg, arg);
> 
> 
>  In all these cases are you really need to use __assign_bit() APIs? I don’t
> see that this goes any higher than 32-bit.
> 
> It’s not a big deal though.

Not really necessary, it just seemed short and good, because it saved
having to spent multiple lines setting/resetting the bit in the variable.


> > +static int wpcm450_gpio_register(struct platform_device *pdev,
> > +                                struct wpcm450_pinctrl *pctrl)
> > +{
> > +       int ret = 0;
> > +       struct fwnode_handle *np;
> 
> 
>  Either be fully OF, or don’t name ‘np' here. We usually use fwnode or
> ‘child’ in this case.

Ah, I thought "np" (= node pointer) was still appropriate because I'm
dealing with firmware _nodes_. My intention was indeed to switch fully
to the fwnode API.


> > +
> > +       pctrl->gpio_base = devm_platform_ioremap_resource(pdev, 0);
> > +       if (!pctrl->gpio_base) {
> > +               dev_err(pctrl->dev, "Resource fail for GPIO controller\n");
> > +               return -ENOMEM;
> 
> 
> dev_err_probe(), ditto for the rest in ->probe().

Oh, I missed these error paths when I changed wpcm450_pinctrl_probe to
dev_err_probe(). I'll go through the rest of the dev_err calls.


> > +       fwnode_for_each_available_child_node(pctrl->dev->fwnode, np) {
> 
> 
> Please, do not dereference fwnode, instead use analogue from device_*()
> APIs. Hence, replace fwnode.h with property.h.

Ok, I'll use device_for_each_child_node() for iteration.


> > +               gpio->gc.of_node = to_of_node(np);
> 
> 
> I hope we will soon have fwnode in gpio_chip.

Yes, that would be good.



> > +               gpio->gc.parent = pctrl->dev;
> >
> >
> Set by bgpio_init(), also check for other potential duplications.

Good catch, I'll check the assignments again.


> > +               ret = gpiochip_add_pin_range(&gpio->gc,
> > dev_name(pctrl->dev),
> > +                                            0, bank->base, bank->length);
> > +               if (ret) {
> > +                       dev_err(pctrl->dev, "Failed to add pin range for
> > GPIO bank %u\n", reg);
> > +                       return ret;
> > +               }
> 
> 
> 
> Please move it to the corresponding callback.

What's the corresponding callback?


> > +               dev_err_probe(&pdev->dev, PTR_ERR(pctrl->pctldev),
> > +                             "Failed to register pinctrl device\n");
> > +               return PTR_ERR(pctrl->pctldev);
> 
> 
> You may combine those two in one return statement.

Good catch, will do.


Thanks for your review,
Jonathan

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

WARNING: multiple messages have this Message-ID (diff)
From: "Jonathan Neuschäfer" <j.neuschaefer@gmx.net>
To: Andy Shevchenko <andy.shevchenko@gmail.com>
Cc: "devicetree@vger.kernel.org" <devicetree@vger.kernel.org>,
	"Tomer Maimon" <tmaimon77@gmail.com>,
	"openbmc@lists.ozlabs.org" <openbmc@lists.ozlabs.org>,
	"Jonathan Neuschäfer" <j.neuschaefer@gmx.net>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	"linux-gpio@vger.kernel.org" <linux-gpio@vger.kernel.org>,
	"Rob Herring" <robh+dt@kernel.org>,
	"Linus Walleij" <linus.walleij@linaro.org>
Subject: Re: [PATCH v2 5/8] pinctrl: nuvoton: Add driver for WPCM450
Date: Wed, 8 Dec 2021 14:58:30 +0100	[thread overview]
Message-ID: <YbC6Bv2teZ5CFhFQ@latitude> (raw)
In-Reply-To: <CAHp75Vew=M_ofNM5pmeHtTJHXRUbbO4RrtgYAtLBznTBm3CS6Q@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 7225 bytes --]

Hi,

On Wed, Dec 08, 2021 at 01:24:18PM +0200, Andy Shevchenko wrote:
> On Tuesday, December 7, 2021, Jonathan Neuschäfer <j.neuschaefer@gmx.net>
> wrote:
> 
> > This driver is based on the one for NPCM7xx, because the WPCM450 is a
> > predecessor of those SoCs. Notable differences:
> >
> > - WPCM450, the GPIO registers are not organized in multiple banks, but
> >   rather placed continually into the same register block. This affects
> >   how register offsets are computed.
> > - Pinmux nodes can explicitly select GPIO mode, whereas, in the npcm7xx
> >   driver, this happens automatically when a GPIO is requested.
> >
> > Some functionality implemented in the hardware was (for now) left unused
> > in the driver, specifically blinking and pull-up/down.
> >
> > Signed-off-by: Jonathan Neuschäfer <j.neuschaefer@gmx.net>
> > ---
[...]
> > +
> > +#include <linux/device.h>
> > +#include <linux/fwnode.h>
> > +#include <linux/gpio/driver.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/irq.h>
> > +#include <linux/mfd/syscon.h>
> > +#include <linux/module.h>
> > +#include <linux/mod_devicetable.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/regmap.h>
> 
> 
> + blank line?

Sounds reasonable, I'll add it.


> > +struct wpcm450_gpio {
> > +       struct wpcm450_pinctrl  *pctrl;
> > +       struct gpio_chip        gc;
> 
> 
> Making this first speeds up pointer arithmetics by making it no-op at
> compile time.

Will do.


> > +static int wpcm450_gpio_irq_bitnum(struct wpcm450_gpio *gpio, struct
> > irq_data *d)
> > +{
> > +       int hwirq = irqd_to_hwirq(d);
> > +
> > +       if (hwirq < gpio->first_irq_gpio)
> > +               return -EINVAL;
> > +
> > +       if (hwirq - gpio->first_irq_gpio >= gpio->num_irqs)
> > +               return -EINVAL;
> > +
> > +       return hwirq - gpio->first_irq_gpio + gpio->first_irq_bit;
> > +}
> > +
> > +static int wpcm450_irq_bitnum_to_gpio(struct wpcm450_gpio *gpio, int
> > bitnum)
> > +{
> > +       if (bitnum < gpio->first_irq_bit)
> > +               return -EINVAL;
> > +
> > +       if (bitnum - gpio->first_irq_bit > gpio->num_irqs)
> > +               return -EINVAL;
> > +
> > +       return bitnum - gpio->first_irq_bit + gpio->first_irq_gpio;
> > +}
> >
> 
> 
> Have you chance to look at bitmap_remap() and bitmap_bitremap() APIs? I’m
> pretty sure you can make this all cleaner by switching to those calls and
> represent the GPIOs as continuous bitmap on the Linux side while on the
> hardware it will be sparse. Check gpio-Xilinx for the details of use.

I haven't looked at it yet in detail, but I'll consider it for the next
iteration.

> > +static void wpcm450_gpio_fix_evpol(struct wpcm450_gpio *gpio, unsigned
> > long all)
> > +{
> 
> 
> 
> What is this quirk (?) for? Please add a comment.

The hardware does not support triggering on both edges, so the trigger
edge polarity has to be adjusted before the next interrupt can work
properly.

I'll add a comment.


> > +static void wpcm450_gpio_irqhandler(struct irq_desc *desc)
> > +{
> > +       struct wpcm450_gpio *gpio = gpiochip_get_data(irq_desc_
> > get_handler_data(desc));
> > +       struct wpcm450_pinctrl *pctrl = gpio->pctrl;
> > +       struct irq_chip *chip = irq_desc_get_chip(desc);
> > +       unsigned long pending;
> > +       unsigned long flags;
> > +       unsigned long ours;
> > +       unsigned int bit;
> > +
> > +       ours = ((1UL << gpio->num_irqs) - 1) << gpio->first_irq_bit;
> 
> 
> BIT()

I'll use it, but in this case, I think it doesn't simplify much the
whole expression all that much. Is there perhaps a macro that
constructs a continuous bitmask of N bits, perhaps additionally
left-shifted by M bits?

Maybe somewhere in the bitmap_* API...


> > +       chained_irq_enter(chip, desc);
> > +       for_each_set_bit(bit, &pending, 32) {
> > +               int offset = wpcm450_irq_bitnum_to_gpio(gpio, bit);
> > +               int irq = irq_find_mapping(gpio->gc.irq.domain, offset);
> > +
> > +               generic_handle_irq(irq);
> 
> 
> Above two are now represented by another generic IRQ handle call, check
> relatively recently updated drivers around.

Will do.

> > +       }
> > +       chained_irq_exit(chip, desc);



> > +               spin_lock_irqsave(&pctrl->lock, flags);
> > +               reg = ioread32(pctrl->gpio_base + WPCM450_GPEVDBNC);
> > +               __assign_bit(bit, &reg, arg);
> 
> 
>  In all these cases are you really need to use __assign_bit() APIs? I don’t
> see that this goes any higher than 32-bit.
> 
> It’s not a big deal though.

Not really necessary, it just seemed short and good, because it saved
having to spent multiple lines setting/resetting the bit in the variable.


> > +static int wpcm450_gpio_register(struct platform_device *pdev,
> > +                                struct wpcm450_pinctrl *pctrl)
> > +{
> > +       int ret = 0;
> > +       struct fwnode_handle *np;
> 
> 
>  Either be fully OF, or don’t name ‘np' here. We usually use fwnode or
> ‘child’ in this case.

Ah, I thought "np" (= node pointer) was still appropriate because I'm
dealing with firmware _nodes_. My intention was indeed to switch fully
to the fwnode API.


> > +
> > +       pctrl->gpio_base = devm_platform_ioremap_resource(pdev, 0);
> > +       if (!pctrl->gpio_base) {
> > +               dev_err(pctrl->dev, "Resource fail for GPIO controller\n");
> > +               return -ENOMEM;
> 
> 
> dev_err_probe(), ditto for the rest in ->probe().

Oh, I missed these error paths when I changed wpcm450_pinctrl_probe to
dev_err_probe(). I'll go through the rest of the dev_err calls.


> > +       fwnode_for_each_available_child_node(pctrl->dev->fwnode, np) {
> 
> 
> Please, do not dereference fwnode, instead use analogue from device_*()
> APIs. Hence, replace fwnode.h with property.h.

Ok, I'll use device_for_each_child_node() for iteration.


> > +               gpio->gc.of_node = to_of_node(np);
> 
> 
> I hope we will soon have fwnode in gpio_chip.

Yes, that would be good.



> > +               gpio->gc.parent = pctrl->dev;
> >
> >
> Set by bgpio_init(), also check for other potential duplications.

Good catch, I'll check the assignments again.


> > +               ret = gpiochip_add_pin_range(&gpio->gc,
> > dev_name(pctrl->dev),
> > +                                            0, bank->base, bank->length);
> > +               if (ret) {
> > +                       dev_err(pctrl->dev, "Failed to add pin range for
> > GPIO bank %u\n", reg);
> > +                       return ret;
> > +               }
> 
> 
> 
> Please move it to the corresponding callback.

What's the corresponding callback?


> > +               dev_err_probe(&pdev->dev, PTR_ERR(pctrl->pctldev),
> > +                             "Failed to register pinctrl device\n");
> > +               return PTR_ERR(pctrl->pctldev);
> 
> 
> You may combine those two in one return statement.

Good catch, will do.


Thanks for your review,
Jonathan

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

  reply	other threads:[~2021-12-08 13:58 UTC|newest]

Thread overview: 53+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-12-07 21:08 [PATCH v2 0/8] Nuvoton WPCM450 pinctrl and GPIO driver Jonathan Neuschäfer
2021-12-07 21:08 ` Jonathan Neuschäfer
2021-12-07 21:08 ` [PATCH v2 1/8] dt-bindings: arm/npcm: Add binding for global control registers (GCR) Jonathan Neuschäfer
2021-12-07 21:08   ` Jonathan Neuschäfer
2021-12-08 13:44   ` Rob Herring
2021-12-08 13:44     ` Rob Herring
2021-12-10 14:54   ` Rob Herring
2021-12-10 14:54     ` Rob Herring
2021-12-12 23:12     ` Jonathan Neuschäfer
2021-12-12 23:12       ` Jonathan Neuschäfer
2021-12-07 21:08 ` [PATCH v2 2/8] MAINTAINERS: Match all of bindings/arm/npcm/ as part of NPCM architecture Jonathan Neuschäfer
2021-12-07 21:08   ` Jonathan Neuschäfer
2021-12-07 21:08 ` [PATCH v2 3/8] ARM: dts: wpcm450: Add global control registers (GCR) node Jonathan Neuschäfer
2021-12-07 21:08   ` Jonathan Neuschäfer
2021-12-07 21:08 ` [PATCH v2 4/8] dt-bindings: pinctrl: Add Nuvoton WPCM450 Jonathan Neuschäfer
2021-12-07 21:08   ` Jonathan Neuschäfer
2021-12-08 13:44   ` Rob Herring
2021-12-08 13:44     ` Rob Herring
2021-12-10 15:18   ` Rob Herring
2021-12-10 15:18     ` Rob Herring
2021-12-12 23:38     ` Jonathan Neuschäfer
2021-12-12 23:38       ` Jonathan Neuschäfer
2021-12-07 21:08 ` [PATCH v2 5/8] pinctrl: nuvoton: Add driver for WPCM450 Jonathan Neuschäfer
2021-12-07 21:08   ` Jonathan Neuschäfer
2021-12-08  0:51   ` kernel test robot
2021-12-08  0:51     ` kernel test robot
2021-12-08  0:51     ` kernel test robot
2021-12-08  2:34   ` kernel test robot
2021-12-08  2:34     ` kernel test robot
2021-12-08  2:34     ` kernel test robot
2021-12-08 11:24   ` Andy Shevchenko
2021-12-08 13:58     ` Jonathan Neuschäfer [this message]
2021-12-08 13:58       ` Jonathan Neuschäfer
2021-12-08 14:14       ` Andy Shevchenko
2021-12-08 14:14         ` Andy Shevchenko
2021-12-12 23:02         ` Jonathan Neuschäfer
2021-12-12 23:02           ` Jonathan Neuschäfer
2021-12-09  8:26       ` Zev Weiss
2021-12-09  8:26         ` Zev Weiss
2021-12-10  1:41         ` Linus Walleij
2021-12-10  1:41           ` Linus Walleij
2021-12-12 23:03           ` Jonathan Neuschäfer
2021-12-12 23:03             ` Jonathan Neuschäfer
2021-12-07 21:08 ` [PATCH v2 6/8] ARM: dts: wpcm450: Add pinctrl and GPIO nodes Jonathan Neuschäfer
2021-12-07 21:08   ` Jonathan Neuschäfer
2021-12-10  1:42   ` Linus Walleij
2021-12-10  1:42     ` Linus Walleij
2021-12-07 21:08 ` [PATCH v2 7/8] ARM: dts: wpcm450: Add pin functions Jonathan Neuschäfer
2021-12-07 21:08   ` Jonathan Neuschäfer
2021-12-07 21:08 ` [PATCH v2 8/8] ARM: dts: wpcm450-supermicro-x9sci-ln4f: Add GPIO LEDs and buttons Jonathan Neuschäfer
2021-12-07 21:08   ` Jonathan Neuschäfer
  -- strict thread matches above, loose matches on Subject: below --
2021-12-09 18:40 [PATCH v2 5/8] pinctrl: nuvoton: Add driver for WPCM450 kernel test robot
2021-12-19  1:24 kernel test robot

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=YbC6Bv2teZ5CFhFQ@latitude \
    --to=j.neuschaefer@gmx.net \
    --cc=andy.shevchenko@gmail.com \
    --cc=devicetree@vger.kernel.org \
    --cc=joel@jms.id.au \
    --cc=linus.walleij@linaro.org \
    --cc=linux-gpio@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=openbmc@lists.ozlabs.org \
    --cc=robh+dt@kernel.org \
    --cc=tmaimon77@gmail.com \
    /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.