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