tech-kern archive

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

gpio interrups (2)



Hello,
here is a second version of my patch to add support for gpio interrupts.
Based on feedback, I improved the allwinner backend.
I also changed the gpio(4) implementation to support a callback
from interrupt context, instead of the thread-based mutex+condvar
(even for my case it's better as it allows me to use sysmon_taskq(9)
instead of a dedicated thread).

I still didn't find a good way to deal with IPLs at this point.
Even pushing the callback suppport to MD code wouldn't work as it would
also need some callback on spllower() and I can't see how to do this.
The API supports a IPL parameter but at this point, only IPL_VM
is allowed.

--  
Manuel Bouyer <bouyer%antioche.eu.org@localhost>
     NetBSD: 26 ans d'experience feront toujours la difference
--
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	25 Apr 2016 17:06:10 -0000
@@ -57,16 +57,7 @@ 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);
-
-#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 @@ 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 +93,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 +106,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 +119,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 +132,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 +145,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 +158,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 +171,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 +185,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 +204,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 +217,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 +230,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 +243,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 +256,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,13 +266,22 @@ static struct awin_gpio_softc {
 	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 @@ awin_gpio_config_pins(device_t self)
 				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 @@ 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 | 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 @@ 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(&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 @@ awin_gpio_update_cfg_regs(bus_space_tag_
 	}
 }
 
+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
 awin_gpio_init(void)
 {
@@ -465,7 +565,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 +676,15 @@ awin_gpio_init(void)
 		    popcount32(grp->grp_pin_mask & ~grp->grp_pin_inuse_mask));
 #endif
 	}
+
+	mutex_init(&sc->sc_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, &sc->sc_eint_bsh);
+	for (u_int i = 0; i < 3; i++) {
+		sc->sc_ecfg[i] = 0;
+	}
+	sc->sc_eintr_configured = 0;
 }
 
 bool
@@ -764,6 +872,7 @@ awin_gpio_pin_ctl(void *cookie, int pin,
 {
 	struct awin_gpio_pin_group * const grp = cookie;
 	struct awin_gpio_pin_cfg ncfg = grp->grp_cfg;
+	struct awin_gpio_softc *sc = &awin_gpio_sc;
 
 	u_int pull_value = AWIN_PIO_PULL_NONE;
 	if (flags & GPIO_PIN_PULLUP) {
@@ -773,16 +882,74 @@ 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(&sc->sc_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(sc, pin,
+				    AWIN_PIO_EINT_LOW_LEVEL);
+			} else {
+				awin_gpio_set_pin_eint(sc, pin,
+				    AWIN_PIO_EINT_HIGH_LEVEL);
+			}
+		} else {
+			if (flags & GPIO_PIN_FALLING) {
+				awin_gpio_set_pin_eint(sc, pin,
+				    AWIN_PIO_EINT_NEGATIVE_EDGE);
+			} else {
+				awin_gpio_set_pin_eint(sc, pin,
+				    AWIN_PIO_EINT_POSITIVE_EDGE);
+			}
+		}
+		awin_gpio_update_eint_regs(sc);
+		sc->sc_eintr_configured |= 1 << pin;
+		awin_gpio_clear_eint(sc, pin);
+	} else { 
+		if ((grp->grp_pin_intr_mask & (1 << pin)) != 0) {
+			sc->sc_eintr_configured &= ~(1 << pin);
+			awin_gpio_update_eint_mask(sc);
+			awin_gpio_clear_eint(sc, 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(&sc->sc_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;
+	struct awin_gpio_softc *sc = &awin_gpio_sc;
+
+	KASSERT(grp->grp_index == 7);
+	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));
+	if (enable)
+		enabled |= (1 << pin);
+	else
+		enabled &= ~(1 << pin);
+	enabled &= sc->sc_eintr_configured;
+	bus_space_write_4(sc->sc_bst, sc->sc_eint_bsh,
+	    INT_OFFSET(AWIN_PIO_INT_CTL_REG), enabled);
+	mutex_exit(&sc->sc_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	25 Apr 2016 17:06:10 -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 },
@@ -190,6 +191,7 @@ static const struct awin_locators awin_l
 	{ "awinir", OFFANDSIZE(IR1), 1, AWIN_IRQ_IR1, A10|A20 },
 	{ "awinir", OFFANDSIZE(A31_CIR), NOPORT, AWIN_A31_IRQ_CIR, A31 },
 	{ "awinir", OFFANDSIZE(A80_CIR), NOPORT, AWIN_A80_IRQ_R_CIR, A80 },
+	{ "awinlradc", OFFANDSIZE(LRADC), NOPORT, AWIN_IRQ_LRADC, A20 },
 };
 
 static int
Index: arch/arm/allwinner/awin_reg.h
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/allwinner/awin_reg.h,v
retrieving revision 1.87
diff -u -p -u -r1.87 awin_reg.h
--- arch/arm/allwinner/awin_reg.h	12 Apr 2016 10:54:29 -0000	1.87
+++ arch/arm/allwinner/awin_reg.h	25 Apr 2016 17:06:10 -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))) 
@@ -3030,4 +3031,44 @@ struct awin_a31_dma_desc {
 
 #define AWIN_A80_PIO_PN_PINS		2
 
+#define AWIN_LRADC_CTRL_REG		0x00
+#define AWIN_LRADC_CTRL_FIRSTCONV_MASK		__BITS(31,24)
+#define AWIN_LRADC_CTRL_FIRSTCONV_SHIFT		24
+#define AWIN_LRADC_CTRL_CHAN_MASK		__BITS(23,22)
+#define AWIN_LRADC_CTRL_CHAN_SHIFT		22
+#define AWIN_LRADC_CTRL_CONT_MASK		__BITS(19,16)
+#define AWIN_LRADC_CTRL_CONT_SHIFT		16
+#define AWIN_LRADC_CTRL_KMODE_MASK		__BITS(13,12)
+#define AWIN_LRADC_CTRL_KMODE_NORMAL		(0 << 12)
+#define AWIN_LRADC_CTRL_KMODE_SINGLE		(1 << 12)
+#define AWIN_LRADC_CTRL_KMODE_CONTINUE		(2 << 12)
+#define AWIN_LRADC_CTRL_LV_A_B_CNT_MASK		__BITS(11,8)
+#define AWIN_LRADC_CTRL_LV_A_B_CNT_SHIFT	8
+#define AWIN_LRADC_CTRL_HOLD_EN			__BIT(6)
+#define AWIN_LRADC_CTRL_LEVEL_B_MASK		__BITS(5,4)
+#define AWIN_LRADC_CTRL_LEVEL_B_3C		(0 << 4)
+#define AWIN_LRADC_CTRL_LEVEL_B_39		(1 << 4)
+#define AWIN_LRADC_CTRL_LEVEL_B_36		(2 << 4)
+#define AWIN_LRADC_CTRL_LEVEL_B_33		(3 << 4)
+#define AWIN_LRADC_CTRL_RATE_MASK		__BITS(3,2)
+#define AWIN_LRADC_CTRL_RATE_250		(0 << 2)
+#define AWIN_LRADC_CTRL_RATE_125		(1 << 2)
+#define AWIN_LRADC_CTRL_RATE_62			(2 << 2)
+#define AWIN_LRADC_CTRL_RATE_31			(3 << 2)
+#define AWIN_LRADC_CTRL_EN			__BIT(0)
+#define AWIN_LRADC_INTC_REG		0x04
+#define AWIN_LRADC_INTS_REG		0x08
+#define AWIN_LRADC_INT_KEYUP1		__BIT(12)
+#define AWIN_LRADC_INT_ALREADYHOLD1	__BIT(11)
+#define AWIN_LRADC_INT_HOLD1		__BIT(10)
+#define AWIN_LRADC_INT_KEY1		__BIT(9)
+#define AWIN_LRADC_INT_DATA1		__BIT(8)
+#define AWIN_LRADC_INT_KEYUP0		__BIT(4)
+#define AWIN_LRADC_INT_ALREADYHOLD0	__BIT(3)
+#define AWIN_LRADC_INT_HOLD0		__BIT(2)
+#define AWIN_LRADC_INT_KEY0		__BIT(1)
+#define AWIN_LRADC_INT_DATA0		__BIT(0)
+#define AWIN_LRADC_DATA0_REG		0x0c
+#define AWIN_LRADC_DATA1_REG		0x10
+
 #endif /* _ARM_ALLWINNER_AWIN_REG_H_ */
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	25 Apr 2016 17:06:12 -0000
@@ -298,6 +298,45 @@ 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);
+	void (*callback)(void *);
+	void *callback_arg;
+
+	for (int i = 0; i < sc->sc_npins; i++) {
+		if (evts & (1 << i)) {
+			mutex_enter(&sc->sc_mtx);
+			callback = sc->sc_pins[i].pin_callback;
+			callback_arg = sc->sc_pins[i].pin_callback_arg;
+			DPRINTFN(2, ("gpio pin %d event callback %p\n", i, callback));
+			if (callback != NULL) {
+				callback(callback_arg);
+			}
+			mutex_exit(&sc->sc_mtx);
+		}
+	}
+}
+
+void *
+gpio_find_device(const char *name)
+{
+	device_t gpio_dev;
+	gpio_dev = device_find_by_xname(name);
+	if (gpio_dev == NULL)
+		return NULL;
+	return device_private(gpio_dev);
+}
+
+const char *
+gpio_get_name(void *gpio)
+{
+	struct gpio_softc *sc = gpio;
+	return device_xname(sc->sc_dev);
+}
+
 /* return 1 if all pins can be mapped, 0 if not */
 int
 gpio_pin_can_map(void *gpio, int offset, uint32_t mask)
@@ -379,8 +418,36 @@ void
 gpio_pin_ctl(void *gpio, struct gpio_pinmap *map, int pin, int flags)
 {
 	struct gpio_softc *sc = gpio;
+	struct gpio_pin *pinp = &sc->sc_pins[map->pm_map[pin]];
+
+	KASSERT((flags & GPIO_PIN_EVENTS) == 0);
+	mutex_enter(&sc->sc_mtx);
+	gpiobus_pin_ctl(sc->sc_gc, map->pm_map[pin], flags);
+	pinp->pin_callback = NULL;
+	pinp->pin_callback_arg = NULL;
+	mutex_exit(&sc->sc_mtx);
+}
 
-	return gpiobus_pin_ctl(sc->sc_gc, map->pm_map[pin], flags);
+void
+gpio_pin_ctl_intr(void *gpio, struct gpio_pinmap *map, int pin, int flags,
+    int ipl, void (*callback)(void *), void *arg)
+{
+	struct gpio_softc *sc = gpio;
+	struct gpio_pin *pinp = &sc->sc_pins[map->pm_map[pin]];
+	KASSERT((flags & GPIO_PIN_EVENTS) != 0);
+	KASSERT(ipl == IPL_VM);
+	mutex_enter(&sc->sc_mtx);
+	pinp->pin_callback = callback;
+	pinp->pin_callback_arg = arg;
+	gpiobus_pin_ctl(sc->sc_gc, map->pm_map[pin], flags);
+	mutex_exit(&sc->sc_mtx);
+}
+
+void
+gpio_pin_irqen(void *gpio, struct gpio_pinmap *map, int pin, bool en)
+{
+	struct gpio_softc *sc = gpio;
+	gpiobus_pin_irqen(sc->sc_gc, map->pm_map[pin], en);
 }
 
 int
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	25 Apr 2016 17:06:12 -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 */
+	void			(*pin_callback)(void *); /* irq callback */
+	void *			pin_callback_arg; /* callback arg */
 } 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 {
@@ -90,16 +95,24 @@ struct gpio_name {
 	LIST_ENTRY(gpio_name)	gp_next;
 };
 
+void *	gpio_find_device(const char *);
+const char * gpio_get_name(void *gpio);
 int	gpio_pin_can_map(void *, int, uint32_t);
 int	gpio_pin_map(void *, int, uint32_t, struct gpio_pinmap *);
 void	gpio_pin_unmap(void *, struct gpio_pinmap *);
 int	gpio_pin_read(void *, struct gpio_pinmap *, int);
 void	gpio_pin_write(void *, struct gpio_pinmap *, int, int);
 void	gpio_pin_ctl(void *, struct gpio_pinmap *, int, int);
+void	gpio_pin_ctl_intr(void *, struct gpio_pinmap *, int, int,
+			int, void (*)(void *), void *);
+void	gpio_pin_irqen(void *, struct gpio_pinmap *, int, bool);
 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_ */


Home | Main Index | Thread Index | Old Index