Re: [PATCH V2 2/3] gpio: xilinx: Add interrupt support

From: Robert Hancock
Date: Fri Jul 24 2020 - 17:37:56 EST


On 2020-07-23 12:03 p.m., Andy Shevchenko wrote:
+/**
+ * xgpio_xlate - Translate gpio_spec to the GPIO number and flags
+ * @gc: Pointer to gpio_chip device structure.
+ * @gpiospec: gpio specifier as found in the device tree
+ * @flags: A flags pointer based on binding
+ *
+ * Return:
+ * irq number otherwise -EINVAL
+ */
+static int xgpio_xlate(struct gpio_chip *gc,
+ const struct of_phandle_args *gpiospec, u32 *flags)
+{
+ if (gc->of_gpio_n_cells < 2) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells))
+ return -EINVAL;
+
+ if (gpiospec->args[0] >= gc->ngpio)
+ return -EINVAL;
+
+ if (flags)
+ *flags = gpiospec->args[1];
+
+ return gpiospec->args[0];
+}

This looks like a very standart xlate function for GPIO. Why do you
need to open-code it?

Indeed, this seems the same as the of_gpio_simple_xlate callback which is used if no xlate callback is specified, so I'm not sure why this is necessary?


...

+/**
+ * xgpio_irq_ack - Acknowledge a child GPIO interrupt.

+ * This currently does nothing, but irq_ack is unconditionally called by
+ * handle_edge_irq and therefore must be defined.

This should go after parameter description(s).

+ * @irq_data: per irq and chip data passed down to chip functions
+ */

...

/**
+ * xgpio_irq_mask - Write the specified signal of the GPIO device.
+ * @irq_data: per irq and chip data passed down to chip functions

In all comments irq -> IRQ.

+ */
+static void xgpio_irq_mask(struct irq_data *irq_data)
+{
+ unsigned long flags;
+ struct xgpio_instance *chip = irq_data_get_irq_chip_data(irq_data);
+ int irq_offset = irqd_to_hwirq(irq_data);
+ int index = xgpio_index(chip, irq_offset);
+ int offset = xgpio_offset(chip, irq_offset);
+
+ spin_lock_irqsave(&chip->gpio_lock, flags);
+

+ chip->irq_enable[index] &= ~BIT(offset);

If you convert your data structure to use bitmaps (and respective API) like

#define XILINX_NGPIOS 64
...
DECLARE_BITMAP(irq_enable, XILINX_NGPIOS);
...

it will make code better to read and understand. For example, here it
will be just
__clear_bit(offset, chip->irq_enable);

+ dev_dbg(chip->gc.parent, "Disable %d irq, irq_enable_mask 0x%x\n",
+ irq_offset, chip->irq_enable[index]);

Under spin lock?! Hmm...

+ if (!chip->irq_enable[index]) {
+ /* Disable per channel interrupt */
+ u32 temp = xgpio_readreg(chip->regs + XGPIO_IPIER_OFFSET);
+
+ temp &= ~BIT(index);
+ xgpio_writereg(chip->regs + XGPIO_IPIER_OFFSET, temp);
+ }
+ spin_unlock_irqrestore(&chip->gpio_lock, flags);
+}

...

+ for (index = 0; index < num_channels; index++) {
+ if ((status & BIT(index))) {

If gpio_width is the same among banks, you can use for_each_set_bit()
here as well.

...

+ for_each_set_bit(bit, &all_events, 32) {
+ generic_handle_irq(irq_find_mapping
+ (chip->gc.irq.domain, offset + bit));

Strange indentation. Maybe a temporary variable helps?

...

+ chip->irq = platform_get_irq_optional(pdev, 0);
+ if (chip->irq <= 0) {
+ dev_info(&pdev->dev, "GPIO IRQ not set\n");

Why do you need an optional variant if you print an error anyway?

+ } else {


...

+ chip->gc.irq.parents = (unsigned int *)&chip->irq;
+ chip->gc.irq.num_parents = 1;

Current pattern is to use devm_kcalloc() for it (Linus has plans to
simplify this in the future and this will help him to find what
patterns are being used)


--
Robert Hancock
Senior Hardware Designer
SED Systems, a division of Calian Ltd.
Email: hancock@xxxxxxxxxxxxx