xref: /openbsd-src/sys/arch/arm64/dev/aplpinctrl.c (revision 7ab4cc9835a16d0789381992ef32a23e35d4fba6)
1*7ab4cc98Skettenis /*	$OpenBSD: aplpinctrl.c,v 1.8 2023/07/23 11:17:50 kettenis Exp $	*/
26eca8e85Skettenis /*
36eca8e85Skettenis  * Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org>
46eca8e85Skettenis  *
56eca8e85Skettenis  * Permission to use, copy, modify, and distribute this software for any
66eca8e85Skettenis  * purpose with or without fee is hereby granted, provided that the above
76eca8e85Skettenis  * copyright notice and this permission notice appear in all copies.
86eca8e85Skettenis  *
96eca8e85Skettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
106eca8e85Skettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
116eca8e85Skettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
126eca8e85Skettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
136eca8e85Skettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
146eca8e85Skettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
156eca8e85Skettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
166eca8e85Skettenis  */
176eca8e85Skettenis 
186eca8e85Skettenis #include <sys/param.h>
196eca8e85Skettenis #include <sys/systm.h>
206eca8e85Skettenis #include <sys/device.h>
21a5e5a65eSkettenis #include <sys/evcount.h>
226eca8e85Skettenis #include <sys/malloc.h>
236eca8e85Skettenis 
246eca8e85Skettenis #include <machine/bus.h>
256eca8e85Skettenis #include <machine/fdt.h>
26a5e5a65eSkettenis #include <machine/intr.h>
276eca8e85Skettenis 
286eca8e85Skettenis #include <dev/ofw/openfirm.h>
29a5e5a65eSkettenis #include <dev/ofw/ofw_gpio.h>
306eca8e85Skettenis #include <dev/ofw/ofw_pinctrl.h>
31*7ab4cc98Skettenis #include <dev/ofw/ofw_power.h>
326eca8e85Skettenis #include <dev/ofw/fdt.h>
336eca8e85Skettenis 
346eca8e85Skettenis #define APPLE_PIN(pinmux) ((pinmux) & 0xffff)
356eca8e85Skettenis #define APPLE_FUNC(pinmux) ((pinmux) >> 16)
366eca8e85Skettenis 
37a5e5a65eSkettenis #define GPIO_PIN(pin)		((pin) * 4)
38a5e5a65eSkettenis #define  GPIO_PIN_GROUP_MASK	(7 << 16)
39a5e5a65eSkettenis #define  GPIO_PIN_INPUT_ENABLE	(1 << 9)
40a5e5a65eSkettenis #define  GPIO_PIN_FUNC_MASK	(3 << 5)
416eca8e85Skettenis #define  GPIO_PIN_FUNC_SHIFT	5
42a5e5a65eSkettenis #define  GPIO_PIN_MODE_MASK	(7 << 1)
43a5e5a65eSkettenis #define  GPIO_PIN_MODE_INPUT	(0 << 1)
44a5e5a65eSkettenis #define  GPIO_PIN_MODE_OUTPUT	(1 << 1)
45a5e5a65eSkettenis #define  GPIO_PIN_MODE_IRQ_HI	(2 << 1)
46a5e5a65eSkettenis #define  GPIO_PIN_MODE_IRQ_LO	(3 << 1)
47a5e5a65eSkettenis #define  GPIO_PIN_MODE_IRQ_UP	(4 << 1)
48a5e5a65eSkettenis #define  GPIO_PIN_MODE_IRQ_DN	(5 << 1)
49a5e5a65eSkettenis #define  GPIO_PIN_MODE_IRQ_ANY	(6 << 1)
50a5e5a65eSkettenis #define  GPIO_PIN_MODE_IRQ_OFF	(7 << 1)
51a5e5a65eSkettenis #define  GPIO_PIN_DATA		(1 << 0)
52a5e5a65eSkettenis #define GPIO_IRQ(grp, pin)	(0x800 + (grp) * 64 + ((pin) >> 5) * 4)
536eca8e85Skettenis 
546eca8e85Skettenis #define HREAD4(sc, reg)						\
556eca8e85Skettenis 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
566eca8e85Skettenis #define HWRITE4(sc, reg, val)						\
576eca8e85Skettenis 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
58a5e5a65eSkettenis #define HSET4(sc, reg, bits)						\
59a5e5a65eSkettenis 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
60a5e5a65eSkettenis #define HCLR4(sc, reg, bits)						\
61a5e5a65eSkettenis 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
62a5e5a65eSkettenis 
63a5e5a65eSkettenis struct intrhand {
641a30e736Skettenis 	TAILQ_ENTRY(intrhand) ih_list;
65a5e5a65eSkettenis 	int (*ih_func)(void *);
66a5e5a65eSkettenis 	void *ih_arg;
67a5e5a65eSkettenis 	int ih_irq;
68a5e5a65eSkettenis 	int ih_type;
69a5e5a65eSkettenis 	int ih_ipl;
70a5e5a65eSkettenis 	struct evcount ih_count;
71a5e5a65eSkettenis 	char *ih_name;
72a5e5a65eSkettenis 	void *ih_sc;
73a5e5a65eSkettenis };
746eca8e85Skettenis 
756eca8e85Skettenis struct aplpinctrl_softc {
766eca8e85Skettenis 	struct device		sc_dev;
776eca8e85Skettenis 	bus_space_tag_t		sc_iot;
786eca8e85Skettenis 	bus_space_handle_t	sc_ioh;
79a5e5a65eSkettenis 
80a5e5a65eSkettenis 	int			sc_ngpios;
81a5e5a65eSkettenis 	struct gpio_controller	sc_gc;
82a5e5a65eSkettenis 
83a5e5a65eSkettenis 	void			*sc_ih;
841a30e736Skettenis 	TAILQ_HEAD(, intrhand)	*sc_handler;
85a5e5a65eSkettenis 	struct interrupt_controller sc_ic;
866eca8e85Skettenis };
876eca8e85Skettenis 
886eca8e85Skettenis int	aplpinctrl_match(struct device *, void *, void *);
896eca8e85Skettenis void	aplpinctrl_attach(struct device *, struct device *, void *);
906eca8e85Skettenis 
91471aeecfSnaddy const struct cfattach aplpinctrl_ca = {
926eca8e85Skettenis 	sizeof (struct aplpinctrl_softc), aplpinctrl_match, aplpinctrl_attach
936eca8e85Skettenis };
946eca8e85Skettenis 
956eca8e85Skettenis struct cfdriver aplpinctrl_cd = {
966eca8e85Skettenis 	NULL, "aplpinctrl", DV_DULL
976eca8e85Skettenis };
986eca8e85Skettenis 
996eca8e85Skettenis int	aplpinctrl_pinctrl(uint32_t, void *);
100a5e5a65eSkettenis void	aplpinctrl_config_pin(void *, uint32_t *, int);
101a5e5a65eSkettenis int	aplpinctrl_get_pin(void *, uint32_t *);
102a5e5a65eSkettenis void	aplpinctrl_set_pin(void *, uint32_t *, int);
103a5e5a65eSkettenis 
104a5e5a65eSkettenis int	aplpinctrl_intr(void *);
105a5e5a65eSkettenis void	*aplpinctrl_intr_establish(void *, int *, int, struct cpu_info *,
106a5e5a65eSkettenis 	    int (*)(void *), void *, char *);
107a5e5a65eSkettenis void	aplpinctrl_intr_disestablish(void *);
108a5e5a65eSkettenis void	aplpinctrl_intr_enable(void *);
109a5e5a65eSkettenis void	aplpinctrl_intr_disable(void *);
110a5e5a65eSkettenis void	aplpinctrl_intr_barrier(void *);
1116eca8e85Skettenis 
1126eca8e85Skettenis int
aplpinctrl_match(struct device * parent,void * match,void * aux)1136eca8e85Skettenis aplpinctrl_match(struct device *parent, void *match, void *aux)
1146eca8e85Skettenis {
1156eca8e85Skettenis 	struct fdt_attach_args *faa = aux;
1166eca8e85Skettenis 
1176eca8e85Skettenis 	return OF_is_compatible(faa->fa_node, "apple,pinctrl");
1186eca8e85Skettenis }
1196eca8e85Skettenis 
1206eca8e85Skettenis void
aplpinctrl_attach(struct device * parent,struct device * self,void * aux)1216eca8e85Skettenis aplpinctrl_attach(struct device *parent, struct device *self, void *aux)
1226eca8e85Skettenis {
1236eca8e85Skettenis 	struct aplpinctrl_softc *sc = (struct aplpinctrl_softc *)self;
1246eca8e85Skettenis 	struct fdt_attach_args *faa = aux;
125a5e5a65eSkettenis 	uint32_t gpio_ranges[4] = {};
1261a30e736Skettenis 	int i;
1276eca8e85Skettenis 
1286eca8e85Skettenis 	if (faa->fa_nreg < 1) {
1296eca8e85Skettenis 		printf(": no registers\n");
1306eca8e85Skettenis 		return;
1316eca8e85Skettenis 	}
1326eca8e85Skettenis 
1336eca8e85Skettenis 	sc->sc_iot = faa->fa_iot;
1346eca8e85Skettenis 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
1356eca8e85Skettenis 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
1366eca8e85Skettenis 		printf(": can't map registers\n");
1376eca8e85Skettenis 		return;
1386eca8e85Skettenis 	}
1396eca8e85Skettenis 
140*7ab4cc98Skettenis 	power_domain_enable(faa->fa_node);
141*7ab4cc98Skettenis 
1426eca8e85Skettenis 	pinctrl_register(faa->fa_node, aplpinctrl_pinctrl, sc);
1436eca8e85Skettenis 
144a5e5a65eSkettenis 	OF_getpropintarray(faa->fa_node, "gpio-ranges",
145a5e5a65eSkettenis 	    gpio_ranges, sizeof(gpio_ranges));
146a5e5a65eSkettenis 	sc->sc_ngpios = gpio_ranges[3];
147a5e5a65eSkettenis 	if (sc->sc_ngpios == 0) {
148a5e5a65eSkettenis 		printf("\n");
149a5e5a65eSkettenis 		return;
150a5e5a65eSkettenis 	}
151a5e5a65eSkettenis 
152a5e5a65eSkettenis 	sc->sc_gc.gc_node = faa->fa_node;
153a5e5a65eSkettenis 	sc->sc_gc.gc_cookie = sc;
154a5e5a65eSkettenis 	sc->sc_gc.gc_config_pin = aplpinctrl_config_pin;
155a5e5a65eSkettenis 	sc->sc_gc.gc_get_pin = aplpinctrl_get_pin;
156a5e5a65eSkettenis 	sc->sc_gc.gc_set_pin = aplpinctrl_set_pin;
157a5e5a65eSkettenis 	gpio_controller_register(&sc->sc_gc);
158a5e5a65eSkettenis 
159a5e5a65eSkettenis 	sc->sc_ih = fdt_intr_establish_idx(faa->fa_node, 0, IPL_BIO,
160a5e5a65eSkettenis 	    aplpinctrl_intr, sc, sc->sc_dev.dv_xname);
161a5e5a65eSkettenis 	if (sc->sc_ih == NULL) {
162a5e5a65eSkettenis 		printf(": can't establish interrupt\n");
163a5e5a65eSkettenis 		return;
164a5e5a65eSkettenis 	}
165a5e5a65eSkettenis 
166a5e5a65eSkettenis 	sc->sc_handler = mallocarray(sc->sc_ngpios,
167a5e5a65eSkettenis 	    sizeof(*sc->sc_handler), M_DEVBUF, M_ZERO | M_WAITOK);
1681a30e736Skettenis 	for (i = 0; i < sc->sc_ngpios; i++)
1691a30e736Skettenis 		TAILQ_INIT(&sc->sc_handler[i]);
170a5e5a65eSkettenis 
171a5e5a65eSkettenis 	sc->sc_ic.ic_node = faa->fa_node;
172a5e5a65eSkettenis 	sc->sc_ic.ic_cookie = sc;
173a5e5a65eSkettenis 	sc->sc_ic.ic_establish = aplpinctrl_intr_establish;
174a5e5a65eSkettenis 	sc->sc_ic.ic_disestablish = aplpinctrl_intr_disestablish;
175a5e5a65eSkettenis 	sc->sc_ic.ic_enable = aplpinctrl_intr_enable;
176a5e5a65eSkettenis 	sc->sc_ic.ic_disable = aplpinctrl_intr_disable;
177a5e5a65eSkettenis 	sc->sc_ic.ic_barrier = aplpinctrl_intr_barrier;
178a5e5a65eSkettenis 	fdt_intr_register(&sc->sc_ic);
179a5e5a65eSkettenis 
1806eca8e85Skettenis 	printf("\n");
1816eca8e85Skettenis }
1826eca8e85Skettenis 
1836eca8e85Skettenis int
aplpinctrl_pinctrl(uint32_t phandle,void * cookie)1846eca8e85Skettenis aplpinctrl_pinctrl(uint32_t phandle, void *cookie)
1856eca8e85Skettenis {
1866eca8e85Skettenis 	struct aplpinctrl_softc *sc = cookie;
1876eca8e85Skettenis 	uint32_t *pinmux;
1886eca8e85Skettenis 	int node, len, i;
1896eca8e85Skettenis 	uint16_t pin, func;
1906eca8e85Skettenis 	uint32_t reg;
1916eca8e85Skettenis 
1926eca8e85Skettenis 	node = OF_getnodebyphandle(phandle);
1936eca8e85Skettenis 	if (node == 0)
1946eca8e85Skettenis 		return -1;
1956eca8e85Skettenis 
1966eca8e85Skettenis 	len = OF_getproplen(node, "pinmux");
1976eca8e85Skettenis 	if (len <= 0)
1986eca8e85Skettenis 		return -1;
1996eca8e85Skettenis 
2006eca8e85Skettenis 	pinmux = malloc(len, M_TEMP, M_WAITOK);
2016eca8e85Skettenis 	OF_getpropintarray(node, "pinmux", pinmux, len);
2026eca8e85Skettenis 
2036eca8e85Skettenis 	for (i = 0; i < len / sizeof(uint32_t); i++) {
2046eca8e85Skettenis 		pin = APPLE_PIN(pinmux[i]);
2056eca8e85Skettenis 		func = APPLE_FUNC(pinmux[i]);
2066eca8e85Skettenis 		reg = HREAD4(sc, GPIO_PIN(pin));
2076eca8e85Skettenis 		reg &= ~GPIO_PIN_FUNC_MASK;
2086eca8e85Skettenis 		reg |= (func << GPIO_PIN_FUNC_SHIFT) & GPIO_PIN_FUNC_MASK;
2096eca8e85Skettenis 		HWRITE4(sc, GPIO_PIN(pin), reg);
2106eca8e85Skettenis 	}
2116eca8e85Skettenis 
2126eca8e85Skettenis 	free(pinmux, M_TEMP, len);
2136eca8e85Skettenis 	return 0;
2146eca8e85Skettenis }
215a5e5a65eSkettenis 
216a5e5a65eSkettenis void
aplpinctrl_config_pin(void * cookie,uint32_t * cells,int config)217a5e5a65eSkettenis aplpinctrl_config_pin(void *cookie, uint32_t *cells, int config)
218a5e5a65eSkettenis {
219a5e5a65eSkettenis 	struct aplpinctrl_softc *sc = cookie;
220a5e5a65eSkettenis 	uint32_t pin = cells[0];
221a5e5a65eSkettenis 	uint32_t reg;
222a5e5a65eSkettenis 
223a5e5a65eSkettenis 	KASSERT(pin < sc->sc_ngpios);
224a5e5a65eSkettenis 
225a5e5a65eSkettenis 	reg = HREAD4(sc, GPIO_PIN(pin));
226a5e5a65eSkettenis 	reg &= ~GPIO_PIN_FUNC_MASK;
227a5e5a65eSkettenis 	reg &= ~GPIO_PIN_MODE_MASK;
228a5e5a65eSkettenis 	if (config & GPIO_CONFIG_OUTPUT)
229a5e5a65eSkettenis 		reg |= GPIO_PIN_MODE_OUTPUT;
230a5e5a65eSkettenis 	else
231a5e5a65eSkettenis 		reg |= GPIO_PIN_MODE_INPUT;
232a5e5a65eSkettenis 	HWRITE4(sc, GPIO_PIN(pin), reg);
233a5e5a65eSkettenis }
234a5e5a65eSkettenis 
235a5e5a65eSkettenis int
aplpinctrl_get_pin(void * cookie,uint32_t * cells)236a5e5a65eSkettenis aplpinctrl_get_pin(void *cookie, uint32_t *cells)
237a5e5a65eSkettenis {
238a5e5a65eSkettenis 	struct aplpinctrl_softc *sc = cookie;
239a5e5a65eSkettenis 	uint32_t pin = cells[0];
240a5e5a65eSkettenis 	uint32_t flags = cells[1];
241a5e5a65eSkettenis 	uint32_t reg;
242a5e5a65eSkettenis 	int val;
243a5e5a65eSkettenis 
244a5e5a65eSkettenis 	KASSERT(pin < sc->sc_ngpios);
245a5e5a65eSkettenis 
246a5e5a65eSkettenis 	reg = HREAD4(sc, GPIO_PIN(pin));
247a5e5a65eSkettenis 	val = !!(reg & GPIO_PIN_DATA);
248a5e5a65eSkettenis 	if (flags & GPIO_ACTIVE_LOW)
249a5e5a65eSkettenis 		val = !val;
250a5e5a65eSkettenis 	return val;
251a5e5a65eSkettenis }
252a5e5a65eSkettenis 
253a5e5a65eSkettenis void
aplpinctrl_set_pin(void * cookie,uint32_t * cells,int val)254a5e5a65eSkettenis aplpinctrl_set_pin(void *cookie, uint32_t *cells, int val)
255a5e5a65eSkettenis {
256a5e5a65eSkettenis 	struct aplpinctrl_softc *sc = cookie;
257a5e5a65eSkettenis 	uint32_t pin = cells[0];
258a5e5a65eSkettenis 	uint32_t flags = cells[1];
259a5e5a65eSkettenis 
260a5e5a65eSkettenis 	KASSERT(pin < sc->sc_ngpios);
261a5e5a65eSkettenis 
262a5e5a65eSkettenis 	if (flags & GPIO_ACTIVE_LOW)
263a5e5a65eSkettenis 		val = !val;
264a5e5a65eSkettenis 	if (val)
265a5e5a65eSkettenis 		HSET4(sc, GPIO_PIN(pin), GPIO_PIN_DATA);
266a5e5a65eSkettenis 	else
267a5e5a65eSkettenis 		HCLR4(sc, GPIO_PIN(pin), GPIO_PIN_DATA);
268a5e5a65eSkettenis }
269a5e5a65eSkettenis 
270a5e5a65eSkettenis int
aplpinctrl_intr(void * arg)271a5e5a65eSkettenis aplpinctrl_intr(void *arg)
272a5e5a65eSkettenis {
273a5e5a65eSkettenis 	struct aplpinctrl_softc *sc = arg;
274a5e5a65eSkettenis 	struct intrhand *ih;
275a5e5a65eSkettenis 	uint32_t status, pending;
2761a30e736Skettenis 	int base, bit, pin, s;
277a5e5a65eSkettenis 
27864dd1569Spatrick 	for (base = 0; base < sc->sc_ngpios; base += 32) {
27964dd1569Spatrick 		status = HREAD4(sc, GPIO_IRQ(0, base));
280a5e5a65eSkettenis 		pending = status;
281a5e5a65eSkettenis 
282a5e5a65eSkettenis 		while (pending) {
2831a30e736Skettenis 			bit = ffs(pending) - 1;
2841a30e736Skettenis 			pin = base + bit;
2851a30e736Skettenis 			TAILQ_FOREACH(ih, &sc->sc_handler[pin], ih_list) {
286a5e5a65eSkettenis 				s = splraise(ih->ih_ipl);
287a5e5a65eSkettenis 				if (ih->ih_func(ih->ih_arg))
288a5e5a65eSkettenis 					ih->ih_count.ec_count++;
289a5e5a65eSkettenis 				splx(s);
290a5e5a65eSkettenis 			}
291a5e5a65eSkettenis 
2921a30e736Skettenis 			pending &= ~(1 << bit);
293a5e5a65eSkettenis 		}
294a5e5a65eSkettenis 
29564dd1569Spatrick 		HWRITE4(sc, GPIO_IRQ(0, base), status);
296a5e5a65eSkettenis 	}
297a5e5a65eSkettenis 
298a5e5a65eSkettenis 	return 1;
299a5e5a65eSkettenis }
300a5e5a65eSkettenis 
301a5e5a65eSkettenis void *
aplpinctrl_intr_establish(void * cookie,int * cells,int ipl,struct cpu_info * ci,int (* func)(void *),void * arg,char * name)302a5e5a65eSkettenis aplpinctrl_intr_establish(void *cookie, int *cells, int ipl,
303a5e5a65eSkettenis     struct cpu_info *ci, int (*func)(void *), void *arg, char *name)
304a5e5a65eSkettenis {
305a5e5a65eSkettenis 	struct aplpinctrl_softc *sc = cookie;
306a5e5a65eSkettenis 	struct intrhand *ih;
307a5e5a65eSkettenis 	uint32_t pin = cells[0];
308a5e5a65eSkettenis 	uint32_t type = IST_NONE;
309a5e5a65eSkettenis 	uint32_t reg;
310a5e5a65eSkettenis 
311a5e5a65eSkettenis 	KASSERT(pin < sc->sc_ngpios);
312a5e5a65eSkettenis 
313a5e5a65eSkettenis 	if (ci != NULL && !CPU_IS_PRIMARY(ci))
314a5e5a65eSkettenis 		return NULL;
315a5e5a65eSkettenis 
316a5e5a65eSkettenis 	switch (cells[1]) {
317a5e5a65eSkettenis 	case 1:
318a5e5a65eSkettenis 		type = IST_EDGE_RISING;
319a5e5a65eSkettenis 		break;
320a5e5a65eSkettenis 	case 2:
321a5e5a65eSkettenis 		type = IST_EDGE_FALLING;
322a5e5a65eSkettenis 		break;
323a5e5a65eSkettenis 	case 3:
324a5e5a65eSkettenis 		type = IST_EDGE_BOTH;
325a5e5a65eSkettenis 		break;
326a5e5a65eSkettenis 	case 4:
327a5e5a65eSkettenis 		type = IST_LEVEL_HIGH;
328a5e5a65eSkettenis 		break;
329a5e5a65eSkettenis 	case 8:
330a5e5a65eSkettenis 		type = IST_LEVEL_LOW;
331a5e5a65eSkettenis 		break;
332a5e5a65eSkettenis 	}
333a5e5a65eSkettenis 
3341a30e736Skettenis 	ih = TAILQ_FIRST(&sc->sc_handler[pin]);
3351a30e736Skettenis 	if (ih && ih->ih_type != type)
3361a30e736Skettenis 		return NULL;
3371a30e736Skettenis 
338a5e5a65eSkettenis 	ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK);
339a5e5a65eSkettenis 	ih->ih_func = func;
340a5e5a65eSkettenis 	ih->ih_arg = arg;
341a5e5a65eSkettenis 	ih->ih_irq = pin;
342a5e5a65eSkettenis 	ih->ih_type = type;
343671f311cSpatrick 	ih->ih_ipl = ipl & IPL_IRQMASK;
344a5e5a65eSkettenis 	ih->ih_name = name;
345a5e5a65eSkettenis 	ih->ih_sc = sc;
346a5e5a65eSkettenis 	if (name != NULL)
347a5e5a65eSkettenis 		evcount_attach(&ih->ih_count, name, &ih->ih_irq);
3481a30e736Skettenis 	TAILQ_INSERT_TAIL(&sc->sc_handler[pin], ih, ih_list);
349a5e5a65eSkettenis 
350a5e5a65eSkettenis 	reg = HREAD4(sc, GPIO_PIN(pin));
351a5e5a65eSkettenis 	reg &= ~GPIO_PIN_DATA;
352a5e5a65eSkettenis 	reg &= ~GPIO_PIN_FUNC_MASK;
353a5e5a65eSkettenis 	reg &= ~GPIO_PIN_MODE_MASK;
354a5e5a65eSkettenis 	switch (type) {
355a5e5a65eSkettenis 	case IST_NONE:
356a5e5a65eSkettenis 		reg |= GPIO_PIN_MODE_IRQ_OFF;
357a5e5a65eSkettenis 		break;
358a5e5a65eSkettenis 	case IST_EDGE_RISING:
359a5e5a65eSkettenis 		reg |= GPIO_PIN_MODE_IRQ_UP;
360a5e5a65eSkettenis 		break;
361a5e5a65eSkettenis 	case IST_EDGE_FALLING:
362a5e5a65eSkettenis 		reg |= GPIO_PIN_MODE_IRQ_DN;
363a5e5a65eSkettenis 		break;
364a5e5a65eSkettenis 	case IST_EDGE_BOTH:
365a5e5a65eSkettenis 		reg |= GPIO_PIN_MODE_IRQ_ANY;
366a5e5a65eSkettenis 		break;
367a5e5a65eSkettenis 	case IST_LEVEL_HIGH:
368a5e5a65eSkettenis 		reg |= GPIO_PIN_MODE_IRQ_HI;
369a5e5a65eSkettenis 		break;
370a5e5a65eSkettenis 	case IST_LEVEL_LOW:
371a5e5a65eSkettenis 		reg |= GPIO_PIN_MODE_IRQ_LO;
372a5e5a65eSkettenis 		break;
373a5e5a65eSkettenis 	}
374a5e5a65eSkettenis 	reg |= GPIO_PIN_INPUT_ENABLE;
375a5e5a65eSkettenis 	reg &= ~GPIO_PIN_GROUP_MASK;
376a5e5a65eSkettenis 	HWRITE4(sc, GPIO_PIN(pin), reg);
377a5e5a65eSkettenis 
378a5e5a65eSkettenis 	return ih;
379a5e5a65eSkettenis }
380a5e5a65eSkettenis 
381a5e5a65eSkettenis void
aplpinctrl_intr_disestablish(void * cookie)382a5e5a65eSkettenis aplpinctrl_intr_disestablish(void *cookie)
383a5e5a65eSkettenis {
384a5e5a65eSkettenis 	struct intrhand *ih = cookie;
385a5e5a65eSkettenis 	struct aplpinctrl_softc *sc = ih->ih_sc;
386a5e5a65eSkettenis 	uint32_t reg;
387a5e5a65eSkettenis 	int s;
388a5e5a65eSkettenis 
389a5e5a65eSkettenis 	s = splhigh();
390a5e5a65eSkettenis 
3911a30e736Skettenis 	TAILQ_REMOVE(&sc->sc_handler[ih->ih_irq], ih, ih_list);
3921a30e736Skettenis 	if (ih->ih_name)
3931a30e736Skettenis 		evcount_detach(&ih->ih_count);
3941a30e736Skettenis 
3951a30e736Skettenis 	if (TAILQ_EMPTY(&sc->sc_handler[ih->ih_irq])) {
396a5e5a65eSkettenis 		reg = HREAD4(sc, GPIO_PIN(ih->ih_irq));
397a5e5a65eSkettenis 		reg &= ~GPIO_PIN_MODE_MASK;
398a5e5a65eSkettenis 		reg |= GPIO_PIN_MODE_IRQ_OFF;
399a5e5a65eSkettenis 		HWRITE4(sc, GPIO_PIN(ih->ih_irq), reg);
4001a30e736Skettenis 	}
401a5e5a65eSkettenis 
402614d6eeaSjsg 	free(ih, M_DEVBUF, sizeof(*ih));
403614d6eeaSjsg 
404a5e5a65eSkettenis 	splx(s);
405a5e5a65eSkettenis }
406a5e5a65eSkettenis 
407a5e5a65eSkettenis void
aplpinctrl_intr_enable(void * cookie)408a5e5a65eSkettenis aplpinctrl_intr_enable(void *cookie)
409a5e5a65eSkettenis {
410a5e5a65eSkettenis 	struct intrhand *ih = cookie;
411a5e5a65eSkettenis 	struct aplpinctrl_softc *sc = ih->ih_sc;
412a5e5a65eSkettenis 	uint32_t reg;
413a5e5a65eSkettenis 	int s;
414a5e5a65eSkettenis 
415a5e5a65eSkettenis 	s = splhigh();
416a5e5a65eSkettenis 	reg = HREAD4(sc, GPIO_PIN(ih->ih_irq));
417a5e5a65eSkettenis 	reg &= ~GPIO_PIN_MODE_MASK;
418a5e5a65eSkettenis 	switch (ih->ih_type) {
419a5e5a65eSkettenis 	case IST_NONE:
420a5e5a65eSkettenis 		reg |= GPIO_PIN_MODE_IRQ_OFF;
421a5e5a65eSkettenis 		break;
422a5e5a65eSkettenis 	case IST_EDGE_RISING:
423a5e5a65eSkettenis 		reg |= GPIO_PIN_MODE_IRQ_UP;
424a5e5a65eSkettenis 		break;
425a5e5a65eSkettenis 	case IST_EDGE_FALLING:
426a5e5a65eSkettenis 		reg |= GPIO_PIN_MODE_IRQ_DN;
427a5e5a65eSkettenis 		break;
428a5e5a65eSkettenis 	case IST_EDGE_BOTH:
429a5e5a65eSkettenis 		reg |= GPIO_PIN_MODE_IRQ_ANY;
430a5e5a65eSkettenis 		break;
431a5e5a65eSkettenis 	case IST_LEVEL_HIGH:
432a5e5a65eSkettenis 		reg |= GPIO_PIN_MODE_IRQ_HI;
433a5e5a65eSkettenis 		break;
434a5e5a65eSkettenis 	case IST_LEVEL_LOW:
435a5e5a65eSkettenis 		reg |= GPIO_PIN_MODE_IRQ_LO;
436a5e5a65eSkettenis 		break;
437a5e5a65eSkettenis 	}
438a5e5a65eSkettenis 	HWRITE4(sc, GPIO_PIN(ih->ih_irq), reg);
439a5e5a65eSkettenis 	splx(s);
440a5e5a65eSkettenis }
441a5e5a65eSkettenis 
442a5e5a65eSkettenis void
aplpinctrl_intr_disable(void * cookie)443a5e5a65eSkettenis aplpinctrl_intr_disable(void *cookie)
444a5e5a65eSkettenis {
445a5e5a65eSkettenis 	struct intrhand *ih = cookie;
446a5e5a65eSkettenis 	struct aplpinctrl_softc *sc = ih->ih_sc;
447a5e5a65eSkettenis 	uint32_t reg;
448a5e5a65eSkettenis 	int s;
449a5e5a65eSkettenis 
450a5e5a65eSkettenis 	s = splhigh();
451a5e5a65eSkettenis 	reg = HREAD4(sc, GPIO_PIN(ih->ih_irq));
452a5e5a65eSkettenis 	reg &= ~GPIO_PIN_MODE_MASK;
453a5e5a65eSkettenis 	reg |= GPIO_PIN_MODE_IRQ_OFF;
454a5e5a65eSkettenis 	HWRITE4(sc, GPIO_PIN(ih->ih_irq), reg);
455a5e5a65eSkettenis 	splx(s);
456a5e5a65eSkettenis }
457a5e5a65eSkettenis 
458a5e5a65eSkettenis void
aplpinctrl_intr_barrier(void * cookie)459a5e5a65eSkettenis aplpinctrl_intr_barrier(void *cookie)
460a5e5a65eSkettenis {
461a5e5a65eSkettenis 	struct intrhand *ih = cookie;
462a5e5a65eSkettenis 	struct aplpinctrl_softc *sc = ih->ih_sc;
463a5e5a65eSkettenis 
464a5e5a65eSkettenis 	intr_barrier(sc->sc_ih);
465a5e5a65eSkettenis }
466