xref: /openbsd-src/sys/dev/fdt/imxgpio.c (revision 671f311c7ba72421460cca4021c1a8e1dad9e2d9)
1*671f311cSpatrick /* $OpenBSD: imxgpio.c,v 1.7 2023/03/05 14:45:07 patrick Exp $ */
25cf2cdabSpatrick /*
35cf2cdabSpatrick  * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
45cf2cdabSpatrick  * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
55cf2cdabSpatrick  *
65cf2cdabSpatrick  * Permission to use, copy, modify, and distribute this software for any
75cf2cdabSpatrick  * purpose with or without fee is hereby granted, provided that the above
85cf2cdabSpatrick  * copyright notice and this permission notice appear in all copies.
95cf2cdabSpatrick  *
105cf2cdabSpatrick  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
115cf2cdabSpatrick  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
125cf2cdabSpatrick  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
135cf2cdabSpatrick  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
145cf2cdabSpatrick  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
155cf2cdabSpatrick  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
165cf2cdabSpatrick  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
175cf2cdabSpatrick  */
185cf2cdabSpatrick 
195cf2cdabSpatrick #include <sys/param.h>
205cf2cdabSpatrick #include <sys/systm.h>
215cf2cdabSpatrick #include <sys/queue.h>
225cf2cdabSpatrick #include <sys/device.h>
235cf2cdabSpatrick #include <sys/malloc.h>
245cf2cdabSpatrick #include <sys/evcount.h>
255cf2cdabSpatrick 
265cf2cdabSpatrick #include <machine/bus.h>
275cf2cdabSpatrick #include <machine/fdt.h>
285cf2cdabSpatrick #include <machine/intr.h>
295cf2cdabSpatrick 
305cf2cdabSpatrick #include <dev/ofw/openfirm.h>
315cf2cdabSpatrick #include <dev/ofw/ofw_gpio.h>
325cf2cdabSpatrick #include <dev/ofw/fdt.h>
335cf2cdabSpatrick 
345cf2cdabSpatrick /* iMX6 registers */
355cf2cdabSpatrick #define GPIO_DR			0x00
365cf2cdabSpatrick #define GPIO_GDIR		0x04
375cf2cdabSpatrick #define GPIO_PSR		0x08
385cf2cdabSpatrick #define GPIO_ICR1		0x0C
395cf2cdabSpatrick #define GPIO_ICR2		0x10
405cf2cdabSpatrick #define GPIO_IMR		0x14
415cf2cdabSpatrick #define GPIO_ISR		0x18
425cf2cdabSpatrick #define GPIO_EDGE_SEL		0x1C
435cf2cdabSpatrick 
445cf2cdabSpatrick #define GPIO_NUM_PINS		32
455cf2cdabSpatrick 
465cf2cdabSpatrick struct intrhand {
475cf2cdabSpatrick 	int (*ih_func)(void *);		/* handler */
485cf2cdabSpatrick 	void *ih_arg;			/* arg for handler */
495cf2cdabSpatrick 	int ih_ipl;			/* IPL_* */
505cf2cdabSpatrick 	int ih_irq;			/* IRQ number */
515cf2cdabSpatrick 	int ih_level;			/* GPIO level */
525cf2cdabSpatrick 	struct evcount	ih_count;
535cf2cdabSpatrick 	char *ih_name;
545cf2cdabSpatrick 	void *ih_sc;
555cf2cdabSpatrick };
565cf2cdabSpatrick 
575cf2cdabSpatrick struct imxgpio_softc {
585cf2cdabSpatrick 	struct device		sc_dev;
595cf2cdabSpatrick 	bus_space_tag_t		sc_iot;
605cf2cdabSpatrick 	bus_space_handle_t	sc_ioh;
615cf2cdabSpatrick 	int			sc_node;
625cf2cdabSpatrick 
635cf2cdabSpatrick 	void			*sc_ih_h;
645cf2cdabSpatrick 	void			*sc_ih_l;
655cf2cdabSpatrick 	int			sc_ipl;
665cf2cdabSpatrick 	int			sc_irq;
675cf2cdabSpatrick 	struct intrhand		*sc_handlers[GPIO_NUM_PINS];
685cf2cdabSpatrick 	struct interrupt_controller sc_ic;
695cf2cdabSpatrick 
705cf2cdabSpatrick 	struct gpio_controller sc_gc;
715cf2cdabSpatrick };
725cf2cdabSpatrick 
735cf2cdabSpatrick int imxgpio_match(struct device *, void *, void *);
745cf2cdabSpatrick void imxgpio_attach(struct device *, struct device *, void *);
755cf2cdabSpatrick 
765cf2cdabSpatrick void imxgpio_config_pin(void *, uint32_t *, int);
775cf2cdabSpatrick int imxgpio_get_pin(void *, uint32_t *);
785cf2cdabSpatrick void imxgpio_set_pin(void *, uint32_t *, int);
795cf2cdabSpatrick 
805cf2cdabSpatrick int imxgpio_intr(void *);
81789e88a4Spatrick void *imxgpio_intr_establish(void *, int *, int, struct cpu_info *,
82789e88a4Spatrick     int (*)(void *), void *, char *);
835cf2cdabSpatrick void imxgpio_intr_disestablish(void *);
845cf2cdabSpatrick void imxgpio_recalc_ipl(struct imxgpio_softc *);
8508dcc7dfSpatrick void imxgpio_intr_enable(void *);
8608dcc7dfSpatrick void imxgpio_intr_disable(void *);
87452daaedSpatrick void imxgpio_intr_barrier(void *);
885cf2cdabSpatrick 
895cf2cdabSpatrick 
909fdf0c62Smpi const struct cfattach	imxgpio_ca = {
915cf2cdabSpatrick 	sizeof (struct imxgpio_softc), imxgpio_match, imxgpio_attach
925cf2cdabSpatrick };
935cf2cdabSpatrick 
945cf2cdabSpatrick struct cfdriver imxgpio_cd = {
955cf2cdabSpatrick 	NULL, "imxgpio", DV_DULL
965cf2cdabSpatrick };
975cf2cdabSpatrick 
985cf2cdabSpatrick int
imxgpio_match(struct device * parent,void * match,void * aux)995cf2cdabSpatrick imxgpio_match(struct device *parent, void *match, void *aux)
1005cf2cdabSpatrick {
1015cf2cdabSpatrick 	struct fdt_attach_args *faa = aux;
1025cf2cdabSpatrick 
1035cf2cdabSpatrick 	return OF_is_compatible(faa->fa_node, "fsl,imx35-gpio");
1045cf2cdabSpatrick }
1055cf2cdabSpatrick 
1065cf2cdabSpatrick void
imxgpio_attach(struct device * parent,struct device * self,void * aux)1075cf2cdabSpatrick imxgpio_attach(struct device *parent, struct device *self, void *aux)
1085cf2cdabSpatrick {
1095cf2cdabSpatrick 	struct imxgpio_softc *sc = (struct imxgpio_softc *)self;
1105cf2cdabSpatrick 	struct fdt_attach_args *faa = aux;
1115cf2cdabSpatrick 
1125cf2cdabSpatrick 	if (faa->fa_nreg < 1)
1135cf2cdabSpatrick 		return;
1145cf2cdabSpatrick 
1155cf2cdabSpatrick 	sc->sc_node = faa->fa_node;
1165cf2cdabSpatrick 	sc->sc_iot = faa->fa_iot;
1175cf2cdabSpatrick 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
1185cf2cdabSpatrick 	    faa->fa_reg[0].size, 0, &sc->sc_ioh))
1195cf2cdabSpatrick 		panic("imxgpio_attach: bus_space_map failed!");
1205cf2cdabSpatrick 
1215cf2cdabSpatrick 	sc->sc_gc.gc_node = faa->fa_node;
1225cf2cdabSpatrick 	sc->sc_gc.gc_cookie = sc;
1235cf2cdabSpatrick 	sc->sc_gc.gc_config_pin = imxgpio_config_pin;
1245cf2cdabSpatrick 	sc->sc_gc.gc_get_pin = imxgpio_get_pin;
1255cf2cdabSpatrick 	sc->sc_gc.gc_set_pin = imxgpio_set_pin;
1265cf2cdabSpatrick 	gpio_controller_register(&sc->sc_gc);
1275cf2cdabSpatrick 
1285cf2cdabSpatrick 	sc->sc_ipl = IPL_NONE;
1295cf2cdabSpatrick 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR, 0);
1305cf2cdabSpatrick 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_ISR, ~0);
1315cf2cdabSpatrick 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_EDGE_SEL, 0);
1325cf2cdabSpatrick 
1335cf2cdabSpatrick 	sc->sc_ic.ic_node = faa->fa_node;
1345cf2cdabSpatrick 	sc->sc_ic.ic_cookie = sc;
1355cf2cdabSpatrick 	sc->sc_ic.ic_establish = imxgpio_intr_establish;
1365cf2cdabSpatrick 	sc->sc_ic.ic_disestablish = imxgpio_intr_disestablish;
13708dcc7dfSpatrick 	sc->sc_ic.ic_enable = imxgpio_intr_enable;
13808dcc7dfSpatrick 	sc->sc_ic.ic_disable = imxgpio_intr_disable;
139452daaedSpatrick 	sc->sc_ic.ic_barrier = imxgpio_intr_barrier;
14070e69ae2Spatrick 	fdt_intr_register(&sc->sc_ic);
1415cf2cdabSpatrick 
1425cf2cdabSpatrick 	printf("\n");
1435cf2cdabSpatrick 
1445cf2cdabSpatrick 	/* XXX - SYSCONFIG */
1455cf2cdabSpatrick 	/* XXX - CTRL */
1465cf2cdabSpatrick 	/* XXX - DEBOUNCE */
1475cf2cdabSpatrick }
1485cf2cdabSpatrick 
1495cf2cdabSpatrick void
imxgpio_config_pin(void * cookie,uint32_t * cells,int config)1505cf2cdabSpatrick imxgpio_config_pin(void *cookie, uint32_t *cells, int config)
1515cf2cdabSpatrick {
1525cf2cdabSpatrick 	struct imxgpio_softc *sc = cookie;
1535cf2cdabSpatrick 	uint32_t pin = cells[0];
1545cf2cdabSpatrick 	uint32_t val;
1555cf2cdabSpatrick 
1565cf2cdabSpatrick 	if (pin >= GPIO_NUM_PINS)
1575cf2cdabSpatrick 		return;
1585cf2cdabSpatrick 
1595cf2cdabSpatrick 	val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_GDIR);
1605cf2cdabSpatrick 	if (config & GPIO_CONFIG_OUTPUT)
1615cf2cdabSpatrick 		val |= 1 << pin;
1625cf2cdabSpatrick 	else
1635cf2cdabSpatrick 		val &= ~(1 << pin);
1645cf2cdabSpatrick 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_GDIR, val);
1655cf2cdabSpatrick }
1665cf2cdabSpatrick 
1675cf2cdabSpatrick int
imxgpio_get_pin(void * cookie,uint32_t * cells)1685cf2cdabSpatrick imxgpio_get_pin(void *cookie, uint32_t *cells)
1695cf2cdabSpatrick {
1705cf2cdabSpatrick 	struct imxgpio_softc *sc = cookie;
1715cf2cdabSpatrick 	uint32_t pin = cells[0];
1725cf2cdabSpatrick 	uint32_t flags = cells[1];
1735cf2cdabSpatrick 	uint32_t reg;
1745cf2cdabSpatrick 	int val;
1755cf2cdabSpatrick 
1765cf2cdabSpatrick 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DR);
1775cf2cdabSpatrick 	reg &= (1 << pin);
1785cf2cdabSpatrick 	val = (reg >> pin) & 1;
1795cf2cdabSpatrick 	if (flags & GPIO_ACTIVE_LOW)
1805cf2cdabSpatrick 		val = !val;
1815cf2cdabSpatrick 	return val;
1825cf2cdabSpatrick }
1835cf2cdabSpatrick 
1845cf2cdabSpatrick void
imxgpio_set_pin(void * cookie,uint32_t * cells,int val)1855cf2cdabSpatrick imxgpio_set_pin(void *cookie, uint32_t *cells, int val)
1865cf2cdabSpatrick {
1875cf2cdabSpatrick 	struct imxgpio_softc *sc = cookie;
1885cf2cdabSpatrick 	uint32_t pin = cells[0];
1895cf2cdabSpatrick 	uint32_t flags = cells[1];
1905cf2cdabSpatrick 	uint32_t reg;
1915cf2cdabSpatrick 
1925cf2cdabSpatrick 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DR);
1935cf2cdabSpatrick 	if (flags & GPIO_ACTIVE_LOW)
1945cf2cdabSpatrick 		val = !val;
1955cf2cdabSpatrick 	if (val)
1965cf2cdabSpatrick 		reg |= (1 << pin);
1975cf2cdabSpatrick 	else
1985cf2cdabSpatrick 		reg &= ~(1 << pin);
1995cf2cdabSpatrick 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_DR, reg);
2005cf2cdabSpatrick }
2015cf2cdabSpatrick 
2025cf2cdabSpatrick int
imxgpio_intr(void * cookie)2035cf2cdabSpatrick imxgpio_intr(void *cookie)
2045cf2cdabSpatrick {
2055cf2cdabSpatrick 	struct imxgpio_softc	*sc = (struct imxgpio_softc *)cookie;
2065cf2cdabSpatrick 	struct intrhand		*ih;
2075cf2cdabSpatrick 	uint32_t		 status, pending, mask;
2085cf2cdabSpatrick 	int			 pin, s;
2095cf2cdabSpatrick 
2105cf2cdabSpatrick 	status = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_ISR);
2115cf2cdabSpatrick 	mask = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR);
2125cf2cdabSpatrick 
2135cf2cdabSpatrick 	status &= mask;
2145cf2cdabSpatrick 	pending = status;
2155cf2cdabSpatrick 
2165cf2cdabSpatrick 	while (pending) {
2175cf2cdabSpatrick 		pin = ffs(pending) - 1;
2185cf2cdabSpatrick 
2195cf2cdabSpatrick 		if ((ih = sc->sc_handlers[pin]) != NULL) {
2205cf2cdabSpatrick 			s = splraise(ih->ih_ipl);
2215cf2cdabSpatrick 			if (ih->ih_func(ih->ih_arg))
2225cf2cdabSpatrick 				ih->ih_count.ec_count++;
2235cf2cdabSpatrick 			splx(s);
2245cf2cdabSpatrick 		}
2255cf2cdabSpatrick 
2265cf2cdabSpatrick 		pending &= ~(1 << pin);
2275cf2cdabSpatrick 	}
2285cf2cdabSpatrick 
2295cf2cdabSpatrick 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_ISR, status);
2305cf2cdabSpatrick 
2315cf2cdabSpatrick 	return 1;
2325cf2cdabSpatrick }
2335cf2cdabSpatrick 
2345cf2cdabSpatrick void *
imxgpio_intr_establish(void * cookie,int * cells,int ipl,struct cpu_info * ci,int (* func)(void *),void * arg,char * name)2355cf2cdabSpatrick imxgpio_intr_establish(void *cookie, int *cells, int ipl,
236789e88a4Spatrick     struct cpu_info *ci, int (*func)(void *), void *arg, char *name)
2375cf2cdabSpatrick {
2385cf2cdabSpatrick 	struct imxgpio_softc	*sc = (struct imxgpio_softc *)cookie;
2395cf2cdabSpatrick 	struct intrhand		*ih;
2405cf2cdabSpatrick 	int			 s, val, reg, shift;
2415cf2cdabSpatrick 	int			 irqno = cells[0];
2425cf2cdabSpatrick 	int			 level = cells[1];
2435cf2cdabSpatrick 
2445cf2cdabSpatrick 	if (irqno < 0 || irqno >= GPIO_NUM_PINS)
2455cf2cdabSpatrick 		panic("%s: bogus irqnumber %d: %s", __func__,
2465cf2cdabSpatrick 		     irqno, name);
2475cf2cdabSpatrick 
2485cf2cdabSpatrick 	if (sc->sc_handlers[irqno] != NULL)
2495cf2cdabSpatrick 		panic("%s: irqnumber %d reused: %s", __func__,
2505cf2cdabSpatrick 		     irqno, name);
2515cf2cdabSpatrick 
252789e88a4Spatrick 	if (ci != NULL && !CPU_IS_PRIMARY(ci))
253789e88a4Spatrick 		return NULL;
254789e88a4Spatrick 
2555cf2cdabSpatrick 	ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK);
2565cf2cdabSpatrick 	ih->ih_func = func;
2575cf2cdabSpatrick 	ih->ih_arg = arg;
258*671f311cSpatrick 	ih->ih_ipl = ipl & IPL_IRQMASK;
2595cf2cdabSpatrick 	ih->ih_irq = irqno;
2605cf2cdabSpatrick 	ih->ih_name = name;
2615cf2cdabSpatrick 	ih->ih_level = level;
2625cf2cdabSpatrick 	ih->ih_sc = sc;
2635cf2cdabSpatrick 
2645cf2cdabSpatrick 	s = splhigh();
2655cf2cdabSpatrick 
2665cf2cdabSpatrick 	sc->sc_handlers[irqno] = ih;
2675cf2cdabSpatrick 
2685cf2cdabSpatrick 	if (name != NULL)
2695cf2cdabSpatrick 		evcount_attach(&ih->ih_count, name, &ih->ih_irq);
2705cf2cdabSpatrick 
2715cf2cdabSpatrick #ifdef DEBUG_INTC
2725cf2cdabSpatrick 	printf("%s: irq %d ipl %d [%s]\n", __func__, ih->ih_irq, ih->ih_ipl,
2735cf2cdabSpatrick 	    ih->ih_name);
2745cf2cdabSpatrick #endif
2755cf2cdabSpatrick 
2765cf2cdabSpatrick 	imxgpio_recalc_ipl(sc);
2775cf2cdabSpatrick 
2785cf2cdabSpatrick 	switch (level) {
2795cf2cdabSpatrick 		case 1: /* rising */
2805cf2cdabSpatrick 			val = 2;
2815cf2cdabSpatrick 			break;
2825cf2cdabSpatrick 		case 2: /* falling */
2835cf2cdabSpatrick 			val = 3;
2845cf2cdabSpatrick 			break;
2855cf2cdabSpatrick 		case 4: /* high */
2865cf2cdabSpatrick 			val = 1;
2875cf2cdabSpatrick 			break;
2885cf2cdabSpatrick 		case 8: /* low */
2895cf2cdabSpatrick 			val = 0;
2905cf2cdabSpatrick 			break;
2915cf2cdabSpatrick 		default:
2925cf2cdabSpatrick 			panic("%s: unsupported trigger type", __func__);
2935cf2cdabSpatrick 	}
2945cf2cdabSpatrick 
2955cf2cdabSpatrick 	if (irqno < 16) {
2965cf2cdabSpatrick 		reg = GPIO_ICR1;
2975cf2cdabSpatrick 		shift = irqno << 1;
2985cf2cdabSpatrick 	} else {
2995cf2cdabSpatrick 		reg = GPIO_ICR2;
3005cf2cdabSpatrick 		shift = (irqno - 16) << 1;
3015cf2cdabSpatrick 	}
3025cf2cdabSpatrick 
3035cf2cdabSpatrick 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, reg,
3045cf2cdabSpatrick 	    bus_space_read_4(sc->sc_iot, sc->sc_ioh, reg) & ~(0x3 << shift));
3055cf2cdabSpatrick 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, reg,
3065cf2cdabSpatrick 	    bus_space_read_4(sc->sc_iot, sc->sc_ioh, reg) | val << shift);
3075cf2cdabSpatrick 
3085cf2cdabSpatrick 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR,
3095cf2cdabSpatrick 	    bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR) | 1 << irqno);
3105cf2cdabSpatrick 
3115cf2cdabSpatrick 	splx(s);
3125cf2cdabSpatrick 	return (ih);
3135cf2cdabSpatrick }
3145cf2cdabSpatrick 
3155cf2cdabSpatrick void
imxgpio_intr_disestablish(void * cookie)3165cf2cdabSpatrick imxgpio_intr_disestablish(void *cookie)
3175cf2cdabSpatrick {
3185cf2cdabSpatrick 	struct intrhand		*ih = cookie;
3195cf2cdabSpatrick 	struct imxgpio_softc	*sc = ih->ih_sc;
3205cf2cdabSpatrick 	uint32_t		 mask;
3215cf2cdabSpatrick 	int			 s;
3225cf2cdabSpatrick 
3235cf2cdabSpatrick 	s = splhigh();
3245cf2cdabSpatrick 
3255cf2cdabSpatrick #ifdef DEBUG_INTC
3265cf2cdabSpatrick 	printf("%s: irq %d ipl %d [%s]\n", __func__, ih->ih_irq, ih->ih_ipl,
3275cf2cdabSpatrick 	    ih->ih_name);
3285cf2cdabSpatrick #endif
3295cf2cdabSpatrick 
3305cf2cdabSpatrick 	mask = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR);
3315cf2cdabSpatrick 	mask &= ~(1 << ih->ih_irq);
3325cf2cdabSpatrick 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR, mask);
3335cf2cdabSpatrick 
3345cf2cdabSpatrick 	sc->sc_handlers[ih->ih_irq] = NULL;
3355cf2cdabSpatrick 	if (ih->ih_name != NULL)
3365cf2cdabSpatrick 		evcount_detach(&ih->ih_count);
3375cf2cdabSpatrick 	free(ih, M_DEVBUF, sizeof(*ih));
3385cf2cdabSpatrick 
3395cf2cdabSpatrick 	imxgpio_recalc_ipl(sc);
3405cf2cdabSpatrick 
3415cf2cdabSpatrick 	splx(s);
3425cf2cdabSpatrick }
3435cf2cdabSpatrick 
3445cf2cdabSpatrick void
imxgpio_recalc_ipl(struct imxgpio_softc * sc)3455cf2cdabSpatrick imxgpio_recalc_ipl(struct imxgpio_softc *sc)
3465cf2cdabSpatrick {
3475cf2cdabSpatrick 	struct intrhand		*ih;
3485cf2cdabSpatrick 	int			 pin;
3495cf2cdabSpatrick 	int			 max = IPL_NONE;
3505cf2cdabSpatrick 	int			 min = IPL_HIGH;
3515cf2cdabSpatrick 
3525cf2cdabSpatrick 	for (pin = 0; pin < GPIO_NUM_PINS; pin++) {
3535cf2cdabSpatrick 		ih = sc->sc_handlers[pin];
3545cf2cdabSpatrick 		if (ih == NULL)
3555cf2cdabSpatrick 			continue;
3565cf2cdabSpatrick 
3575cf2cdabSpatrick 		if (ih->ih_ipl > max)
3585cf2cdabSpatrick 			max = ih->ih_ipl;
3595cf2cdabSpatrick 
3605cf2cdabSpatrick 		if (ih->ih_ipl < min)
3615cf2cdabSpatrick 			min = ih->ih_ipl;
3625cf2cdabSpatrick 	}
3635cf2cdabSpatrick 
3645cf2cdabSpatrick 	if (max == IPL_NONE)
3655cf2cdabSpatrick 		min = IPL_NONE;
3665cf2cdabSpatrick 
3675cf2cdabSpatrick 	if (sc->sc_ipl != max) {
3685cf2cdabSpatrick 		sc->sc_ipl = max;
3695cf2cdabSpatrick 
3705cf2cdabSpatrick 		if (sc->sc_ih_l != NULL)
37170e69ae2Spatrick 			fdt_intr_disestablish(sc->sc_ih_l);
3725cf2cdabSpatrick 
3735cf2cdabSpatrick 		if (sc->sc_ih_h != NULL)
37470e69ae2Spatrick 			fdt_intr_disestablish(sc->sc_ih_h);
3755cf2cdabSpatrick 
3765cf2cdabSpatrick 		if (sc->sc_ipl != IPL_NONE) {
37770e69ae2Spatrick 			sc->sc_ih_l = fdt_intr_establish_idx(sc->sc_node, 0,
3785cf2cdabSpatrick 			    sc->sc_ipl, imxgpio_intr, sc, sc->sc_dev.dv_xname);
37970e69ae2Spatrick 			sc->sc_ih_h = fdt_intr_establish_idx(sc->sc_node, 1,
3805cf2cdabSpatrick 			    sc->sc_ipl, imxgpio_intr, sc, sc->sc_dev.dv_xname);
3815cf2cdabSpatrick 		}
3825cf2cdabSpatrick 	}
3835cf2cdabSpatrick }
38408dcc7dfSpatrick 
38508dcc7dfSpatrick void
imxgpio_intr_enable(void * cookie)38608dcc7dfSpatrick imxgpio_intr_enable(void *cookie)
38708dcc7dfSpatrick {
38808dcc7dfSpatrick 	struct intrhand		*ih = cookie;
38908dcc7dfSpatrick 	struct imxgpio_softc	*sc = ih->ih_sc;
39008dcc7dfSpatrick 	uint32_t		 mask;
39108dcc7dfSpatrick 	int			 s;
39208dcc7dfSpatrick 
39308dcc7dfSpatrick 	s = splhigh();
39408dcc7dfSpatrick 	mask = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR);
39508dcc7dfSpatrick 	mask |= (1 << ih->ih_irq);
39608dcc7dfSpatrick 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR, mask);
39708dcc7dfSpatrick 	splx(s);
39808dcc7dfSpatrick }
39908dcc7dfSpatrick 
40008dcc7dfSpatrick void
imxgpio_intr_disable(void * cookie)40108dcc7dfSpatrick imxgpio_intr_disable(void *cookie)
40208dcc7dfSpatrick {
40308dcc7dfSpatrick 	struct intrhand		*ih = cookie;
40408dcc7dfSpatrick 	struct imxgpio_softc	*sc = ih->ih_sc;
40508dcc7dfSpatrick 	uint32_t		 mask;
40608dcc7dfSpatrick 	int			 s;
40708dcc7dfSpatrick 
40808dcc7dfSpatrick 	s = splhigh();
40908dcc7dfSpatrick 	mask = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR);
41008dcc7dfSpatrick 	mask &= ~(1 << ih->ih_irq);
41108dcc7dfSpatrick 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_IMR, mask);
41208dcc7dfSpatrick 	splx(s);
41308dcc7dfSpatrick }
414452daaedSpatrick 
415452daaedSpatrick void
imxgpio_intr_barrier(void * cookie)416452daaedSpatrick imxgpio_intr_barrier(void *cookie)
417452daaedSpatrick {
418452daaedSpatrick 	struct intrhand		*ih = cookie;
419452daaedSpatrick 	struct imxgpio_softc	*sc = ih->ih_sc;
420452daaedSpatrick 
421452daaedSpatrick 	if (sc->sc_ih_h && ih->ih_irq >= 16)
422452daaedSpatrick 		intr_barrier(sc->sc_ih_h);
423452daaedSpatrick 	else if (sc->sc_ih_l)
424452daaedSpatrick 		intr_barrier(sc->sc_ih_l);
425452daaedSpatrick }
426