Re: [PATCH 10/16] gpio: add driver for Atheros AR2315 SoC GPIO controller

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Linus,

thank you for so detailed review!

I have one more generic question: could you merge driver without
GPIOLIB_IRQCHIP usage? Currently no one driver for the AR231x SoCs
uses irq_domain and I do not like to enable IRQ_DOMAIN just for one
driver. I plan to convert drivers to make them irq_domain aware a bit
later.

Please, find my comments below.

2014-10-15 12:58 GMT+04:00, Linus Walleij <linus.walleij@xxxxxxxxxx>:
> On Sun, Sep 28, 2014 at 8:33 PM, Sergey Ryazanov <ryazanov.s.a@xxxxxxxxx>
> wrote:
>
>> Atheros AR2315 SoC have a builtin GPIO controller, which could be
>> accessed via memory mapped registers. This patch adds new driver
>> for them.
>>
>> Signed-off-by: Sergey Ryazanov <ryazanov.s.a@xxxxxxxxx>
>> Cc: Linus Walleij <linus.walleij@xxxxxxxxxx>
>> Cc: Alexandre Courbot <gnurou@xxxxxxxxx>
>> Cc: linux-gpio@xxxxxxxxxxxxxxx
>
>> +config GPIO_AR2315
>> +       bool "AR2315 SoC GPIO support"
>> +       default y if SOC_AR2315
>> +       depends on SOC_AR2315
>> +       help
>> +         Say yes here to enable GPIO support for Atheros AR2315+ SoCs.
>
> select GPIOLIB_IRQCHIP
>
> As far as I can see this driver should use the gpiolib irqchip helpers
> and create a cascading irqchip. The code uses some copy/pasting
> from earlier drivers which is not a good idea. Look at one of the drivers
> using GPIOLIB_IRQCHIP and be inspired, check e.g. gpio-pl061.c
> or gpio-zynq.c
>
Yes, this driver is pretty old, I updated it with newer API except
IRQ_DOMAIN, which I left for stage 2. Thank you for your hint about
reference realization.

>> +static u32 ar2315_gpio_intmask;
>> +static u32 ar2315_gpio_intval;
>> +static unsigned ar2315_gpio_irq_base;
>> +static void __iomem *ar2315_mem;
>
> No static locals. Allocate and use a state container, see
> Documentation/driver-model/design-patterns.txt
>
Is that rule mandatory for drivers, which serve only one device?

>> +static inline u32 ar2315_gpio_reg_read(unsigned reg)
>> +{
>> +       return __raw_readl(ar2315_mem + reg);
>> +}
>
> Use readl_relaxed() instead.
>
readl_relaxed() converts the bit ordering and seems inapplicable in this case.

>> +static inline void ar2315_gpio_reg_write(unsigned reg, u32 val)
>> +{
>> +       __raw_writel(val, ar2315_mem + reg);
>> +}
>
> Use writel_relaxed() instead.
>
> When you use the state container, you need to do a
> state dereference like that:
>
> mystate->base + reg
>
> So I don't think these inlines buy you anything. Just use
> readl/writel_relaxed directly in the code.
>
These helpers make code shorter and clearer. I can use macros if you
do preferred.

>> +static inline void ar2315_gpio_reg_mask(unsigned reg, u32 mask, u32 val)
>> +{
>> +       ar2315_gpio_reg_write(reg, (ar2315_gpio_reg_read(reg) & ~mask) |
>> val);
>> +}
>
> Too simple helper IMO, if you wanna do this in some organized fashion,
> use regmap.
>
>> +static void ar2315_gpio_int_setup(unsigned gpio, int trig)
>> +{
>> +       u32 reg = ar2315_gpio_reg_read(AR2315_GPIO_INT);
>> +
>> +       reg &= ~(AR2315_GPIO_INT_NUM_M | AR2315_GPIO_INT_TRIG_M);
>> +       reg |= gpio | AR2315_GPIO_INT_TRIG(trig);
>> +       ar2315_gpio_reg_write(AR2315_GPIO_INT, reg);
>> +}
>
> Trig? Isn't this supposed to be done in the .set_type()
> callback?
>
Yep. I tried to cheat kernel and made as if driver does not supports
any other trigger types :)

>> +static void ar2315_gpio_irq_unmask(struct irq_data *d)
>> +{
>> +       unsigned gpio = d->irq - ar2315_gpio_irq_base;
>
> This kind of weird calculations go away with irqdomain and that
> is in turn used by GPIOLIB_IRQCHIP.
>
> After that you will just use d->hwirq. And name the variable
> "offset" while you're at it.
>
>> +       u32 dir = ar2315_gpio_reg_read(AR2315_GPIO_DIR);
>> +
>> +       /* Enable interrupt with edge detection */
>> +       if ((dir & AR2315_GPIO_DIR_M(gpio)) != AR2315_GPIO_DIR_I(gpio))
>> +               return;
>> +
>> +       ar2315_gpio_intmask |= (1 << gpio);
>
> #include <linux/bitops.h>
>
> ar2315_gpio_intmask |= BIT(gpio);
>
>> +       ar2315_gpio_int_setup(gpio, AR2315_GPIO_INT_TRIG_EDGE);
>> +}
>
>> +static struct irq_chip ar2315_gpio_irq_chip = {
>> +       .name           = DRIVER_NAME,
>> +       .irq_unmask     = ar2315_gpio_irq_unmask,
>> +       .irq_mask       = ar2315_gpio_irq_mask,
>> +};
>
> So why is .set_type() not implemented and instead hard-coded into
> the unmask function? Please fix this. It will be called by the
> core eventually no matter what.
>
The interrupt configuration is a bit complex. This controller could be
configured to generate interrupts only for two lines at once. Or in
other words: user could select any two lines to generate interrupt.

>> +static void ar2315_gpio_irq_init(unsigned irq)
>> +{
>> +       unsigned i;
>> +
>> +       ar2315_gpio_intval = ar2315_gpio_reg_read(AR2315_GPIO_DI);
>> +       for (i = 0; i < AR2315_GPIO_NUM; i++) {
>> +               unsigned _irq = ar2315_gpio_irq_base + i;
>> +
>> +               irq_set_chip_and_handler(_irq, &ar2315_gpio_irq_chip,
>> +                                        handle_level_irq);
>> +       }
>> +       irq_set_chained_handler(irq, ar2315_gpio_irq_handler);
>> +}
>
> No, use the gpiolib irqchip helpers.
>
>> +static int ar2315_gpio_get_val(struct gpio_chip *chip, unsigned gpio)
>> +{
>> +       return (ar2315_gpio_reg_read(AR2315_GPIO_DI) >> gpio) & 1;
>> +}
>
> Do this instead:
>
> return !!(ar2315_gpio_reg_read(AR2315_GPIO_DI) & BIT(offset));
>
>> +static int ar2315_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
>> +{
>> +       return ar2315_gpio_irq_base + gpio;
>> +}
>
> You do not implement this at all when using the gpiolib irqchip helpers.
>
>> +static int ar2315_gpio_probe(struct platform_device *pdev)
>> +{
>> +       struct device *dev = &pdev->dev;
>> +       struct resource *res;
>> +       unsigned irq;
>> +       int ret;
>> +
>> +       if (ar2315_mem)
>> +               return -EBUSY;
>> +
>> +       res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
>> DRIVER_NAME);
>> +       if (!res) {
>> +               dev_err(dev, "not found IRQ number\n");
>> +               return -ENXIO;
>> +       }
>> +       irq = res->start;
>
> Use
>
> irq = platform_get_irq_byname(pdev, DRIVER_NAME);
> if (irq < 0)...
>
>> +       ret = irq_alloc_descs(-1, 0, AR2315_GPIO_NUM, 0);
>> +       if (ret < 0) {
>> +               dev_err(dev, "failed to allocate IRQ numbers\n");
>> +               return ret;
>> +       }
>> +       ar2315_gpio_irq_base = ret;
>> +
>> +       ar2315_gpio_irq_init(irq);
>
> No, let GPIOLIB_IRQCHIP handle this.
>
>> +static int __init ar2315_gpio_init(void)
>> +{
>> +       return platform_driver_register(&ar2315_gpio_driver);
>> +}
>> +subsys_initcall(ar2315_gpio_init);
>
> Why are you using subsys_initcall()?
>
> This should not be necessary.
>
I have users of GPIO in arch code, what called earlier than the
devices initcall.

> Yours,
> Linus Walleij
>

-- 
BR,
Sergey
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux SPI]     [Linux Kernel]     [Linux ARM (vger)]     [Linux ARM MSM]     [Linux Omap]     [Linux Arm]     [Linux Tegra]     [Fedora ARM]     [Linux for Samsung SOC]     [eCos]     [Linux Fastboot]     [Gcc Help]     [Git]     [DCCP]     [IETF Announce]     [Security]     [Linux MIPS]     [Yosemite Campsites]

  Powered by Linux