Source-Changes-HG archive

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

[src/trunk]: src/sys As proposed in



details:   https://anonhg.NetBSD.org/src/rev/bc1e0c7a7374
branches:  trunk
changeset: 345179:bc1e0c7a7374
user:      bouyer <bouyer%NetBSD.org@localhost>
date:      Wed May 11 18:33:40 2016 +0000

description:
As proposed in
http://mail-index.netbsd.org/tech-kern/2016/04/28/msg020504.html
add gpio interrupt support to the gpio framework, and an implementation
for the allwinner gpio backend (tested on A20 only).
gpio(4) has new public functions:
- gpio_intr() called by backends when an interrupt condition for
  a gpio pin is present
- gpio_find_device() and gpio_get_name(), support functions for
  gpio(4) users, wich respectively returns a void * cookie for a gpio device
  given its name, and returns the name given the cookie.
- gpio_pin_ctl_intr(), which is used to configure interrupts on a gpio pin and
  registers a callback.
- gpio_pin_irqen(), which is used to mask/unmask interrupts on a pin.

Nothing in the NetBSD tree uses this yet, but I have a i2c driver
(at https://github.com/mbouyer/marine_chartplotter/tree/master/software/NetBSD/driver) which uses it.

diffstat:

 sys/arch/arm/allwinner/awin_gpio.c |  201 +++++++++++++++++++++++++++++++++---
 sys/arch/arm/allwinner/awin_io.c   |    5 +-
 sys/arch/arm/allwinner/awin_reg.h  |    3 +-
 sys/dev/gpio/gpio.c                |   79 +++++++++++++-
 sys/dev/gpio/gpiovar.h             |   15 ++-
 5 files changed, 279 insertions(+), 24 deletions(-)

diffs (truncated from 620 to 300 lines):

diff -r 0684c9cb1527 -r bc1e0c7a7374 sys/arch/arm/allwinner/awin_gpio.c
--- a/sys/arch/arm/allwinner/awin_gpio.c        Wed May 11 17:48:05 2016 +0000
+++ b/sys/arch/arm/allwinner/awin_gpio.c        Wed May 11 18:33:40 2016 +0000
@@ -35,7 +35,7 @@
 
 #include <sys/cdefs.h>
 
-__KERNEL_RCSID(1, "$NetBSD: awin_gpio.c,v 1.20 2015/10/02 16:04:40 bouyer Exp $");
+__KERNEL_RCSID(1, "$NetBSD: awin_gpio.c,v 1.21 2016/05/11 18:33:40 bouyer Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -57,16 +57,7 @@
 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);
-
-#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
+static void awin_gpio_pin_irqen(void *, int, bool);
 
 struct awin_gpio_pin_cfg {
        uint32_t cfg[4];
@@ -77,16 +68,19 @@
 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 +93,7 @@
        [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 +106,7 @@
        [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 +119,7 @@
        [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 +132,7 @@
        [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 +145,7 @@
        [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 +158,7 @@
        [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 +171,13 @@
        [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 +185,7 @@
        [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 +204,7 @@
                        .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 +217,7 @@
                        .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 +230,7 @@
                        .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 +243,7 @@
                        .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 +256,7 @@
                        .gp_pin_ctl = awin_gpio_pin_ctl,
                },
                .grp_pin_mask = 0,
+               .grp_pin_intr_mask = 0,
                .grp_nc_name = "nc-pn",
        },
 };
@@ -258,13 +266,22 @@
        device_t sc_dev;
        bus_space_tag_t sc_bst;
        bus_space_handle_t sc_bsh;
+       bus_space_handle_t sc_eint_bsh;
+       void *sc_ih;
+       kmutex_t sc_intr_lock;
+       uint32_t sc_ecfg[4];
+       uint32_t sc_eintr_configured;
 } awin_gpio_sc = {
        .sc_bst = &armv7_generic_bs_tag,
 };
 
+#define INT_OFFSET(x) ((x) - AWIN_PIO_INT_CFG0_REG)
+
 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,20 @@
                                pin->pin_num = num + (i << 5);
                                pin->pin_caps = pincaps;
                                pin->pin_flags = pincaps;
+                               if ((grp->grp_pin_intr_mask & (1 << num)) != 0){
+                                       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 +396,15 @@
 
        aprint_naive("\n");
        aprint_normal("\n");
+       sc->sc_ih = intr_establish(loc->loc_intr,
+           IPL_VM, IST_LEVEL | IST_MPSAFE,
+           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 +426,32 @@
 #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(&sc->sc_intr_lock);
+       enabled = bus_space_read_4(sc->sc_bst, sc->sc_eint_bsh,
+           INT_OFFSET(AWIN_PIO_INT_CTL_REG));
+       pending = bus_space_read_4(sc->sc_bst, sc->sc_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, sc->sc_eint_bsh,
+           INT_OFFSET(AWIN_PIO_INT_CTL_REG), enabled);
+       bus_space_write_4(sc->sc_bst, sc->sc_eint_bsh,
+           INT_OFFSET(AWIN_PIO_INT_STA_REG), pending);
+       mutex_exit(&sc->sc_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 +516,47 @@
        }
 }
 
+static void
+awin_gpio_set_pin_eint(struct awin_gpio_softc *sc, int pin, uint32_t m)
+{
+       int g = (pin >> 3);
+       int s = ((pin & 7) * 4);
+       KASSERT(g < 4);
+       sc->sc_ecfg[g] &= ~(0xf << s);
+       sc->sc_ecfg[g] |= ((m & 0xf) << s);
+}
+
+static void
+awin_gpio_update_eint_regs(struct awin_gpio_softc *sc)
+{
+       int i;
+
+       KASSERT(mutex_owned(&sc->sc_intr_lock));
+       for (i = 0; i < 4; i++) {
+               bus_space_write_4(sc->sc_bst, sc->sc_eint_bsh, i * 4,
+                   sc->sc_ecfg[i]);
+       }
+}
+
+static void
+awin_gpio_clear_eint(struct awin_gpio_softc *sc, int pin)
+{
+               bus_space_write_4(sc->sc_bst, sc->sc_eint_bsh,
+                   INT_OFFSET(AWIN_PIO_INT_STA_REG), (1U <<pin));
+}
+
+static void
+awin_gpio_update_eint_mask(struct awin_gpio_softc *sc)
+{
+       uint32_t enabled;
+       KASSERT(mutex_owned(&sc->sc_intr_lock));
+       enabled = bus_space_read_4(sc->sc_bst, sc->sc_eint_bsh,
+                   INT_OFFSET(AWIN_PIO_INT_CTL_REG));
+       enabled &= sc->sc_eintr_configured;
+       bus_space_write_4(sc->sc_bst, sc->sc_eint_bsh,
+                   INT_OFFSET(AWIN_PIO_INT_CTL_REG), enabled);
+}
+
 void



Home | Main Index | Thread Index | Old Index