Hello,
I have a setup where an external device needs to interrupt an A20 CPU:
the device is also connected to the A20 via I2C and raise the IRQ line
when it needs attention.

The EINT* pins of the A20 are also GPIOs, and as this I2c device is not
allwinner-specific I think the best way to go it to add interrupt support
to gpio(4). some time ago mlelstv@ added some flags to sys/gpio.h that 
go in this direction.

The attached patch adds two functions to gpio.c:
gpio_pin_wait() is called by a thread that wants to wait on an interrupt.
A thread can wait only on a single pin.

gpio_intr() is called from backends when an interrupt-enabled gpio is
triggered. Multiple pins events can be signaled in a single call.

The backend provides an additionnal callback: gp_pin_irqen(), called by
gpio(4) to mask/unmask an interrupt on a specific pin.
the backend masks pending interrupts before calling gpio_intr(),
and gpio_pin_wait() has to explicitely unmask the interrupt before waiting.

Code is missing to properly support detach, I'll add it if what I already done
doens't require major changes.

I don't need to have userland wait on interrupts; this could be added but
I don't know yet what the best way to do it would be (an ioctl or a
kevent?).

The attached patch also has the implementation for the allwinner backend,
limited to A20 at this time (I don't have other hardware to test)

-- 
Manuel Bouyer <bou...@antioche.eu.org>
     NetBSD: 26 ans d'experience feront toujours la difference
--
Index: dev/gpio/gpio.c
===================================================================
RCS file: /cvsroot/src/sys/dev/gpio/gpio.c,v
retrieving revision 1.57
diff -u -p -u -r1.57 gpio.c
--- dev/gpio/gpio.c     25 Jul 2014 08:10:36 -0000      1.57
+++ dev/gpio/gpio.c     7 Apr 2016 11:28:26 -0000
@@ -216,6 +216,9 @@ gpio_attach(device_t parent, device_t se
        mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_VM);
        cv_init(&sc->sc_ioctl, "gpioctl");
        cv_init(&sc->sc_attach, "gpioatch");
+       for (int i = 0; i < sc->sc_npins; i++) {
+               cv_init(&sc->sc_pins[i].pin_cv, "gpioev");
+       }
        /*
         * Attach all devices that can be connected to the GPIO pins
         * described in the kernel configuration file.
@@ -235,6 +238,9 @@ gpio_detach(device_t self, int flags)
                return rc;
        mutex_destroy(&sc->sc_mtx);
        cv_destroy(&sc->sc_ioctl);
+       for (int i = 0; i < sc->sc_npins; i++) {
+               cv_destroy(&sc->sc_pins[i].pin_cv);
+       }
 #if 0
        int maj, mn;
 
@@ -298,6 +304,48 @@ gpiobus_print(void *aux, const char *pnp
        return UNCONF;
 }
 
+/* called from backends when a interrupt even occurs */
+void
+gpio_intr(device_t self, uint32_t evts)
+{
+       struct gpio_softc *sc = device_private(self);
+       for (int i = 0; i < sc->sc_npins; i++) {
+               if (evts & (1 << i)) {
+                       DPRINTFN(2, ("gpio pin %d event\n", i));
+                       mutex_enter(&sc->sc_mtx);
+                       sc->sc_pins[i].pin_ev_pending = 1;
+                       cv_signal(&sc->sc_pins[i].pin_cv);
+                       mutex_exit(&sc->sc_mtx);
+               }
+       }
+}
+
+/* wait for an event on a pin to occur. Must be called from thread context */
+int
+gpio_pin_wait(void *gpio, int pin)
+{
+       struct gpio_softc *sc = gpio;
+       int error;
+       if (pin >= sc->sc_npins) {
+               return ERANGE;
+       }
+       error = 0;
+       gpiobus_pin_irqen(sc->sc_gc, pin, 1);
+       mutex_enter(&sc->sc_mtx);
+       while (!sc->sc_pins[pin].pin_ev_pending) {
+               DPRINTFN(2, ("wait on pin %d\n", pin));
+               error = cv_wait_sig(&sc->sc_pins[pin].pin_cv, &sc->sc_mtx);
+               if (error) {
+                       mutex_exit(&sc->sc_mtx);
+                       gpiobus_pin_irqen(sc->sc_gc, pin, 0);
+                       return error;
+               }
+       }
+       sc->sc_pins[pin].pin_ev_pending = 0;
+       mutex_exit(&sc->sc_mtx);
+       return 0;
+}
+
 /* return 1 if all pins can be mapped, 0 if not */
 int
 gpio_pin_can_map(void *gpio, int offset, uint32_t mask)
Index: dev/gpio/gpiovar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/gpio/gpiovar.h,v
retrieving revision 1.15
diff -u -p -u -r1.15 gpiovar.h
--- dev/gpio/gpiovar.h  13 Nov 2011 13:20:02 -0000      1.15
+++ dev/gpio/gpiovar.h  7 Apr 2016 11:28:26 -0000
@@ -31,6 +31,7 @@ typedef struct gpio_chipset_tag {
        int     (*gp_pin_read)(void *, int);
        void    (*gp_pin_write)(void *, int, int);
        void    (*gp_pin_ctl)(void *, int, int);
+       void    (*gp_pin_irqen)(void *, int, bool);
 } *gpio_chipset_tag_t;
 
 /* GPIO pin description */
@@ -41,6 +42,8 @@ typedef struct gpio_pin {
        int                     pin_state;      /* current state */
        int                     pin_mapped;     /* is mapped */
        gpio_chipset_tag_t      pin_gc;         /* reference the controller */
+       kcondvar_t              pin_cv;         /* for GPIO_PIN_EVENTS */
+       bool                    pin_ev_pending; /* an event is pending */
 } gpio_pin_t;
 
 /* Attach GPIO framework to the controller */
@@ -63,6 +66,8 @@ int gpiobus_print(void *, const char *);
     ((gc)->gp_pin_write((gc)->gp_cookie, (pin), (value)))
 #define gpiobus_pin_ctl(gc, pin, flags) \
     ((gc)->gp_pin_ctl((gc)->gp_cookie, (pin), (flags)))
+#define gpiobus_pin_irqen(gc, pin, en) \
+    ((gc)->gp_pin_irqen((gc)->gp_cookie, (pin), (en)))
 
 /* Attach devices connected to the GPIO pins */
 struct gpio_attach_args {
@@ -97,9 +102,12 @@ int gpio_pin_read(void *, struct gpio_pi
 void   gpio_pin_write(void *, struct gpio_pinmap *, int, int);
 void   gpio_pin_ctl(void *, struct gpio_pinmap *, int, int);
 int    gpio_pin_caps(void *, struct gpio_pinmap *, int);
+int    gpio_pin_wait(void *, int);
 int    gpio_npins(uint32_t);
 
 int    gpio_lock(void *);
 void   gpio_unlock(void *);
 
+void   gpio_intr(device_t, u_int32_t);
+
 #endif /* !_DEV_GPIO_GPIOVAR_H_ */
Index: arch/arm/allwinner/awin_gpio.c
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/allwinner/awin_gpio.c,v
retrieving revision 1.20
diff -u -p -u -r1.20 awin_gpio.c
--- arch/arm/allwinner/awin_gpio.c      2 Oct 2015 16:04:40 -0000       1.20
+++ arch/arm/allwinner/awin_gpio.c      7 Apr 2016 11:28:26 -0000
@@ -57,17 +57,14 @@ static void awin_gpio_attach(device_t, d
 static int awin_gpio_pin_read(void *, int);
 static void awin_gpio_pin_write(void *, int, int);
 static void awin_gpio_pin_ctl(void *, int, int);
+static void awin_gpio_pin_irqen(void *, int, bool);
 
-#if 0
-static const int ist_maps[] = {
-       [IST_LEVEL_LOW] =       AWIN_PIO_EINT_LOW_LEVEL,
-       [IST_LEVEL_HIGH] =      AWIN_PIO_EINT_HIGH_LEVEL,
-       [IST_EDGE_FALLING] =    AWIN_PIO_EINT_POSITIVE_EDGE,
-       [IST_EDGE_RISING] =     AWIN_PIO_EINT_NEGATIVE_EDGE,
-       [IST_EDGE_BOTH] =       AWIN_PIO_EINT_DOUBLE_EDGE,
-};
-#endif
-
+kmutex_t awin_gpio_intr_lock;
+uint32_t awin_gpio_ecfg[3];
+uint32_t awin_gpio_eintr_configured;
+bus_space_handle_t awin_gpio_eint_bsh;
+#define INT_OFFSET(x) ((x) - AWIN_PIO_INT_CFG0_REG)
+       
 struct awin_gpio_pin_cfg {
        uint32_t cfg[4];
        uint32_t drv[2];
@@ -77,16 +74,19 @@ struct awin_gpio_pin_cfg {
 static struct awin_gpio_pin_group {
        bus_addr_t grp_offset;
        uint32_t grp_pin_mask;
+       uint32_t grp_pin_intr_mask;
        uint32_t grp_pin_inuse_mask;
        bus_space_handle_t grp_bsh;
        struct awin_gpio_pin_cfg grp_cfg;
        struct gpio_chipset_tag grp_gc_tag;
        const int grp_index;
        const char grp_nc_name[6];
+       device_t grp_gpio_dev;
 } pin_groups[] = {
        [0] = {
                .grp_offset = AWIN_PIO_OFFSET + 0 * AWIN_PIO_GRP_SIZE,
                .grp_pin_mask = __BIT(AWIN_PIO_PA_PINS) - 1,
+               .grp_pin_intr_mask = 0,
                .grp_gc_tag = {
                        .gp_cookie = &pin_groups[0],
                        .gp_pin_read = awin_gpio_pin_read,
@@ -99,6 +99,7 @@ static struct awin_gpio_pin_group {
        [1] = {
                .grp_offset = AWIN_PIO_OFFSET + 1 * AWIN_PIO_GRP_SIZE,
                .grp_pin_mask = __BIT(AWIN_PIO_PB_PINS) - 1,
+               .grp_pin_intr_mask = 0,
                .grp_gc_tag = {
                        .gp_cookie = &pin_groups[1],
                        .gp_pin_read = awin_gpio_pin_read,
@@ -111,6 +112,7 @@ static struct awin_gpio_pin_group {
        [2] = {
                .grp_offset = AWIN_PIO_OFFSET + 2 * AWIN_PIO_GRP_SIZE,
                .grp_pin_mask = __BIT(AWIN_PIO_PC_PINS) - 1,
+               .grp_pin_intr_mask = 0,
                .grp_gc_tag = {
                        .gp_cookie = &pin_groups[2],
                        .gp_pin_read = awin_gpio_pin_read,
@@ -123,6 +125,7 @@ static struct awin_gpio_pin_group {
        [3] = {
                .grp_offset = AWIN_PIO_OFFSET + 3 * AWIN_PIO_GRP_SIZE,
                .grp_pin_mask = __BIT(AWIN_PIO_PD_PINS) - 1,
+               .grp_pin_intr_mask = 0,
                .grp_gc_tag = {
                        .gp_cookie = &pin_groups[3],
                        .gp_pin_read = awin_gpio_pin_read,
@@ -135,6 +138,7 @@ static struct awin_gpio_pin_group {
        [4] = {
                .grp_offset = AWIN_PIO_OFFSET + 4 * AWIN_PIO_GRP_SIZE,
                .grp_pin_mask = __BIT(AWIN_PIO_PE_PINS) - 1,
+               .grp_pin_intr_mask = 0,
                .grp_gc_tag = {
                        .gp_cookie = &pin_groups[4],
                        .gp_pin_read = awin_gpio_pin_read,
@@ -147,6 +151,7 @@ static struct awin_gpio_pin_group {
        [5] = {
                .grp_offset = AWIN_PIO_OFFSET + 5 * AWIN_PIO_GRP_SIZE,
                .grp_pin_mask = __BIT(AWIN_PIO_PF_PINS) - 1,
+               .grp_pin_intr_mask = 0,
                .grp_gc_tag = {
                        .gp_cookie = &pin_groups[5],
                        .gp_pin_read = awin_gpio_pin_read,
@@ -159,6 +164,7 @@ static struct awin_gpio_pin_group {
        [6] = {
                .grp_offset = AWIN_PIO_OFFSET + 6 * AWIN_PIO_GRP_SIZE,
                .grp_pin_mask = __BIT(AWIN_PIO_PG_PINS) - 1,
+               .grp_pin_intr_mask = 0,
                .grp_gc_tag = {
                        .gp_cookie = &pin_groups[6],
                        .gp_pin_read = awin_gpio_pin_read,
@@ -171,11 +177,13 @@ static struct awin_gpio_pin_group {
        [7] = {
                .grp_offset = AWIN_PIO_OFFSET + 7 * AWIN_PIO_GRP_SIZE,
                .grp_pin_mask = __BIT(AWIN_PIO_PH_PINS) - 1,
+               .grp_pin_intr_mask = AWIN_PIO_PH_EINT_PINS,
                .grp_gc_tag = {
                        .gp_cookie = &pin_groups[7],
                        .gp_pin_read = awin_gpio_pin_read,
                        .gp_pin_write = awin_gpio_pin_write,
                        .gp_pin_ctl = awin_gpio_pin_ctl,
+                       .gp_pin_irqen = awin_gpio_pin_irqen,
                },
                .grp_index = 7,
                .grp_nc_name = "nc-ph",
@@ -183,6 +191,7 @@ static struct awin_gpio_pin_group {
        [8] = {
                .grp_offset = AWIN_PIO_OFFSET + 8 * AWIN_PIO_GRP_SIZE,
                .grp_pin_mask = __BIT(AWIN_PIO_PI_PINS) - 1,
+               .grp_pin_intr_mask = 0,
                .grp_gc_tag = {
                        .gp_cookie = &pin_groups[8],
                        .gp_pin_read = awin_gpio_pin_read,
@@ -201,6 +210,7 @@ static struct awin_gpio_pin_group {
                        .gp_pin_ctl = awin_gpio_pin_ctl,
                },
                .grp_pin_mask = 0,
+               .grp_pin_intr_mask = 0,
                .grp_index = 9,
                .grp_nc_name = "nc-pj",
        },
@@ -213,6 +223,7 @@ static struct awin_gpio_pin_group {
                        .gp_pin_ctl = awin_gpio_pin_ctl,
                },
                .grp_pin_mask = 0,
+               .grp_pin_intr_mask = 0,
                .grp_index = 10,
                .grp_nc_name = "nc-pk",
        },
@@ -225,6 +236,7 @@ static struct awin_gpio_pin_group {
                        .gp_pin_ctl = awin_gpio_pin_ctl,
                },
                .grp_pin_mask = 0,
+               .grp_pin_intr_mask = 0,
                .grp_index = 11,
                .grp_nc_name = "nc-pl",
        },
@@ -237,6 +249,7 @@ static struct awin_gpio_pin_group {
                        .gp_pin_ctl = awin_gpio_pin_ctl,
                },
                .grp_pin_mask = 0,
+               .grp_pin_intr_mask = 0,
                .grp_index = 12,
                .grp_nc_name = "nc-pm",
        },
@@ -249,6 +262,7 @@ static struct awin_gpio_pin_group {
                        .gp_pin_ctl = awin_gpio_pin_ctl,
                },
                .grp_pin_mask = 0,
+               .grp_pin_intr_mask = 0,
                .grp_nc_name = "nc-pn",
        },
 };
@@ -258,6 +272,7 @@ static struct awin_gpio_softc {
        device_t sc_dev;
        bus_space_tag_t sc_bst;
        bus_space_handle_t sc_bsh;
+       void *sc_ih;
 } awin_gpio_sc = {
        .sc_bst = &armv7_generic_bs_tag,
 };
@@ -265,6 +280,8 @@ static struct awin_gpio_softc {
 CFATTACH_DECL_NEW(awin_gpio, sizeof(struct awin_gpio_softc),
        awin_gpio_match, awin_gpio_attach, NULL, NULL);
 
+static int awin_gpio_intr(void *);
+
 static int
 awin_gpio_match(device_t parent, cfdata_t cf, void *aux)
 {
@@ -345,13 +362,23 @@ awin_gpio_config_pins(device_t self)
                                pin->pin_num = num + (i << 5);
                                pin->pin_caps = pincaps;
                                pin->pin_flags = pincaps;
+                               if (grp->grp_index == 7 &&
+                                   num <= 21 && 
+                                   awin_chip_id() == AWIN_CHIP_ID_A20) {
+                                       /* PH0-21 can do interrupts */
+                                       pin->pin_caps |=
+                                           GPIO_PIN_EVENTS |
+                                           GPIO_PIN_LEVEL |
+                                           GPIO_PIN_FALLING;
+                               }
                                pin->pin_state = (data & 1) != 0;
                                pin++;
                        }
                }
 
                gba.gba_npins = pin - gba.gba_pins;
-               config_found_ia(self, "gpiobus", &gba, awin_gpio_cfprint);
+               grp->grp_gpio_dev =
+                   config_found_ia(self, "gpiobus", &gba, awin_gpio_cfprint);
        }
 }
 #endif /* NGPIO > 0 */
@@ -372,6 +399,14 @@ awin_gpio_attach(device_t parent, device
 
        aprint_naive("\n");
        aprint_normal("\n");
+       sc->sc_ih = intr_establish(loc->loc_intr, IPL_VM, IST_LEVEL,
+           awin_gpio_intr, &awin_gpio_sc);
+       if (sc->sc_ih == NULL) {
+               aprint_error_dev(self, "failed to establish interrupt %d\n",
+                   loc->loc_intr);
+               return;
+       }
+       aprint_normal_dev(self, "interrupting on irq %d\n", loc->loc_intr);
 
        for (u_int i = 0; i < __arraycount(pin_groups); i++) {
                struct awin_gpio_pin_group * const grp = &pin_groups[i];
@@ -393,6 +428,32 @@ awin_gpio_attach(device_t parent, device
 #endif
 }
 
+static int
+awin_gpio_intr(void *a)
+{
+       struct awin_gpio_softc *sc = a;
+       uint32_t enabled;
+       uint32_t pending;
+       struct awin_gpio_pin_group * const grp = &pin_groups[7]; /* XXX */
+       
+       mutex_enter(&awin_gpio_intr_lock);
+       enabled = bus_space_read_4(sc->sc_bst, awin_gpio_eint_bsh,
+           INT_OFFSET(AWIN_PIO_INT_CTL_REG));
+       pending = bus_space_read_4(sc->sc_bst, awin_gpio_eint_bsh,
+           INT_OFFSET(AWIN_PIO_INT_STA_REG));
+       /* keep only enabled interrupts */
+       pending &= enabled;
+       /* mask and ack pending interrupts */
+       enabled &= ~pending;
+       bus_space_write_4(sc->sc_bst, awin_gpio_eint_bsh,
+           INT_OFFSET(AWIN_PIO_INT_CTL_REG), enabled);
+       bus_space_write_4(sc->sc_bst, awin_gpio_eint_bsh,
+           INT_OFFSET(AWIN_PIO_INT_STA_REG), pending);
+       mutex_exit(&awin_gpio_intr_lock);
+       gpio_intr(grp->grp_gpio_dev, pending);
+       return 1;
+}
+
 static u_int
 awin_gpio_get_pin_func(const struct awin_gpio_pin_cfg *cfg, u_int pin)
 {
@@ -457,6 +518,48 @@ awin_gpio_update_cfg_regs(bus_space_tag_
        }
 }
 
+static void
+awin_gpio_set_pin_eint(int pin, uint32_t m)
+{
+       int g = (pin >> 3);
+       int s = ((pin & 7) * 4);
+       KASSERT(g <= 3);
+       KASSERT(s <= 28);
+       awin_gpio_ecfg[g] &= ~(0xf << s);
+       awin_gpio_ecfg[g] |= ((m & 0xf) << s);
+}
+
+static void
+awin_gpio_update_eint_regs(bus_space_tag_t bst)
+{
+       int i;
+
+       KASSERT(mutex_owned(&awin_gpio_intr_lock));
+       for (i = 0; i < 4; i++) {
+               bus_space_write_4(bst, awin_gpio_eint_bsh, i * 4,
+                   awin_gpio_ecfg[i]);
+       }
+}
+
+static void
+awin_gpio_clear_eint(bus_space_tag_t bst, int pin)
+{
+               bus_space_write_4(bst, awin_gpio_eint_bsh,
+                   INT_OFFSET(AWIN_PIO_INT_STA_REG), (1U <<pin));
+}
+
+static void
+awin_gpio_update_eint_mask(bus_space_tag_t bst)
+{
+       uint32_t enabled;
+       KASSERT(mutex_owned(&awin_gpio_intr_lock));
+       enabled = bus_space_read_4(bst, awin_gpio_eint_bsh,
+                   INT_OFFSET(AWIN_PIO_INT_CTL_REG));
+       enabled &= awin_gpio_eintr_configured;
+       bus_space_write_4(bst, awin_gpio_eint_bsh,
+                   INT_OFFSET(AWIN_PIO_INT_CTL_REG), enabled);
+}
+
 void
 awin_gpio_init(void)
 {
@@ -465,7 +568,6 @@ awin_gpio_init(void)
 #ifdef VERBOSE_INIT_ARM
        printf(" free");
 #endif
-
        if (awin_chip_id() == AWIN_CHIP_ID_A31) {
                pin_groups[0].grp_pin_mask = __BIT(AWIN_A31_PIO_PA_PINS) - 1;
                pin_groups[1].grp_pin_mask = __BIT(AWIN_A31_PIO_PB_PINS) - 1;
@@ -577,6 +679,15 @@ awin_gpio_init(void)
                    popcount32(grp->grp_pin_mask & ~grp->grp_pin_inuse_mask));
 #endif
        }
+
+       mutex_init(&awin_gpio_intr_lock, MUTEX_DEFAULT, IPL_VM);
+       bus_space_subregion(sc->sc_bst, awin_core_bsh,
+           AWIN_PIO_OFFSET + AWIN_PIO_INT_CFG0_REG,
+           AWIN_PIO_INT_SIZE, &awin_gpio_eint_bsh);
+       for (u_int i = 0; i < 3; i++) {
+               awin_gpio_ecfg[i] = 0;
+       }
+       awin_gpio_eintr_configured = 0;
 }
 
 bool
@@ -773,16 +884,73 @@ awin_gpio_pin_ctl(void *cookie, int pin,
        }
        awin_gpio_set_pin_pull(&ncfg, pin, pull_value);
 
-       if (flags & GPIO_PIN_INPUT) {
-               awin_gpio_set_pin_func(&ncfg, pin, AWIN_PIO_FUNC_INPUT);
-       } else if (flags & GPIO_PIN_OUTPUT) {
-               awin_gpio_set_pin_func(&ncfg, pin, AWIN_PIO_FUNC_OUTPUT);
+       mutex_enter(&awin_gpio_intr_lock);
+       if (flags & GPIO_PIN_EVENTS) {
+               KASSERT(awin_chip_id() == AWIN_CHIP_ID_A20);
+               KASSERT(grp->grp_index == 7);
+               KASSERT(pin <= 21);
+               KASSERT((grp->grp_pin_intr_mask & (1 << pin)) != 0);
+               awin_gpio_set_pin_func(&ncfg, pin, AWIN_PIO_PH_EINT_FUNC);
+               if (flags & GPIO_PIN_LEVEL) {
+                       if (flags & GPIO_PIN_FALLING) {
+                               awin_gpio_set_pin_eint(pin,
+                                   AWIN_PIO_EINT_LOW_LEVEL);
+                       } else {
+                               awin_gpio_set_pin_eint(pin,
+                                   AWIN_PIO_EINT_HIGH_LEVEL);
+                       }
+               } else {
+                       if (flags & GPIO_PIN_FALLING) {
+                               awin_gpio_set_pin_eint(pin,
+                                   AWIN_PIO_EINT_NEGATIVE_EDGE);
+                       } else {
+                               awin_gpio_set_pin_eint(pin,
+                                   AWIN_PIO_EINT_POSITIVE_EDGE);
+                       }
+               }
+               awin_gpio_update_eint_regs(&armv7_generic_bs_tag);
+               awin_gpio_eintr_configured |= 1 << pin;
+               awin_gpio_clear_eint(&armv7_generic_bs_tag, pin);
+       } else { 
+               if ((grp->grp_pin_intr_mask & (1 << pin)) != 0) {
+                       awin_gpio_eintr_configured &= ~(1 << pin);
+                       awin_gpio_update_eint_mask(&armv7_generic_bs_tag);
+                       awin_gpio_clear_eint(&armv7_generic_bs_tag, pin);
+               }
+               if (flags & GPIO_PIN_INPUT) {
+                       awin_gpio_set_pin_func(&ncfg, pin,
+                           AWIN_PIO_FUNC_INPUT);
+               } else if (flags & GPIO_PIN_OUTPUT) {
+                       awin_gpio_set_pin_func(&ncfg, pin,
+                           AWIN_PIO_FUNC_OUTPUT);
+               }
        }
 
        /*
         * Now update any config register that changed.
         */
        awin_gpio_update_cfg_regs(&armv7_generic_bs_tag, grp, &ncfg);
+       mutex_exit(&awin_gpio_intr_lock);
+}
+
+static void
+awin_gpio_pin_irqen(void *cookie, int pin, bool enable)
+{
+       struct awin_gpio_pin_group * const grp = cookie;
+       uint32_t enabled;
+
+       KASSERT(grp->grp_index == 7);
+       mutex_enter(&awin_gpio_intr_lock);
+       enabled = bus_space_read_4(&armv7_generic_bs_tag, awin_gpio_eint_bsh,
+           INT_OFFSET(AWIN_PIO_INT_CTL_REG));
+       if (enable)
+               enabled |= (1 << pin);
+       else
+               enabled &= ~(1 << pin);
+       enabled &= awin_gpio_eintr_configured;
+       bus_space_write_4(&armv7_generic_bs_tag, awin_gpio_eint_bsh,
+           INT_OFFSET(AWIN_PIO_INT_CTL_REG), enabled);
+       mutex_exit(&awin_gpio_intr_lock);
 }
 
 bool
Index: arch/arm/allwinner/awin_io.c
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/allwinner/awin_io.c,v
retrieving revision 1.44
diff -u -p -u -r1.44 awin_io.c
--- arch/arm/allwinner/awin_io.c        26 Dec 2015 16:56:41 -0000      1.44
+++ arch/arm/allwinner/awin_io.c        7 Apr 2016 11:28:26 -0000
@@ -97,7 +97,8 @@ awinio_print(void *aux, const char *pnp)
 
 static const struct awin_locators awin_locators[] = {
        { "awinicu", OFFANDSIZE(INTC), NOPORT, NOINTR, A10|REQ },
-       { "awingpio", OFFANDSIZE(PIO), NOPORT, NOINTR, A10|A20|A31|REQ },
+       { "awingpio", OFFANDSIZE(PIO), NOPORT, AWIN_IRQ_PIO, A10|A20|REQ },
+       { "awingpio", OFFANDSIZE(PIO), NOPORT, NOINTR, A31|REQ },
        { "awingpio", OFFANDSIZE(A80_PIO), NOPORT, NOINTR, A80|REQ },
        { "awindma", OFFANDSIZE(DMA), NOPORT, AWIN_IRQ_DMA, A10|A20 },
        { "awindma", OFFANDSIZE(DMA), NOPORT, AWIN_A31_IRQ_DMA, A31 },
Index: arch/arm/allwinner/awin_reg.h
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/allwinner/awin_reg.h,v
retrieving revision 1.86
diff -u -p -u -r1.86 awin_reg.h
--- arch/arm/allwinner/awin_reg.h       11 Jan 2016 17:09:25 -0000      1.86
+++ arch/arm/allwinner/awin_reg.h       7 Apr 2016 11:28:26 -0000
@@ -1293,6 +1293,7 @@ struct awin_mmc_idma_descriptor {
 #define AWIN_PIO_INT_DEB_REG           0x0218
 #define AWIN_PIO_SDR_PAD_DEV_REG       0x0220
 #define AWIN_PIO_SDR_PAD_PUL_REG       0x0224
+#define AWIN_PIO_INT_SIZE              0x0028
 
 #define AWIN_PIO_CFG_PINMASK(pin)      (7 << (4*((pin) & 7)))
 #define AWIN_PIO_DRV_MASK(pin)         ((x) << (2*((pin) & 15))) 

Reply via email to