Thread (1 message) 1 message, 1 author, 2011-12-18

Re: [PATCH 1/2] gpio: add a driver for the Synopsys DesignWare APB GPIO block

From: Linus Walleij <hidden>
Date: 2011-12-18 22:01:38
Also in: linux-arm-kernel

On Sun, Dec 18, 2011 at 11:13 AM, Jamie Iles [off-list ref] wrote:
The Synopsys DesignWare block is used in some ARM devices (picoxcell)
and can be configured to provide multiple banks of GPIO pins.  The first
bank (A) can also provide IRQ capabilities.
Overall this is looking good.

Here is a problem (I think):
+static int dwapb_irq_set_type(struct irq_data *d, u32 type)
+{
+       struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+       struct dwapb_gpio *gpio = gc->private;
+       int bit = d->hwirq;
+       unsigned long level, polarity;
+
+       if (type & ~(IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
+                    IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
+               return -EINVAL;
+
+       level = readl(gpio->regs + INT_TYPE_REG_OFFS);
+       polarity = readl(gpio->regs + INT_POLARITY_REG_OFFS);
+
+       if (type & IRQ_TYPE_EDGE_RISING) {
+               level |= (1 << bit);
+               polarity |= (1 << bit);
+       } else if (type & IRQ_TYPE_EDGE_FALLING) {
+               level |= (1 << bit);
+               polarity &= ~(1 << bit);
So what if you get request for *both* falling and rising edges?

This is not uncommon at all, for example a GPIO which detecs
MMC card insertions and removals like drivers/host/mmc/mmci.c
will want interrupts on both edges since we want to change state
whenever the card is inserted *or* removed.

If you check drivers/gpio/gpio-u300.c you can see how I handled
this on another hardware where triggering on falling and rising
edges was a binary choice and thus mutually exclusive: I toggle
for each interrupt.

See u300_toggle_trigger(), u300_gpio_irq_type().

So either you do something like that, or you detect both set
and return an error, else the poor caller will just get falling
edges in this driver...
+       } else if (type & IRQ_TYPE_LEVEL_HIGH) {
+               level &= ~(1 << bit);
+               polarity |= (1 << bit);
+       } else if (type & IRQ_TYPE_LEVEL_LOW) {
+               level &= ~(1 << bit);
+               polarity &= ~(1 << bit);
+       }
This is OK though, these are mutually exclusive.

Yours,
Linus Walleij
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help