xref: /freebsd-src/sys/arm/mv/gpio.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
1373bbe25SRafal Jaworowski /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3af3dc4a7SPedro F. Giffuni  *
4373bbe25SRafal Jaworowski  * Copyright (c) 2006 Benno Rice.
5373bbe25SRafal Jaworowski  * Copyright (C) 2008 MARVELL INTERNATIONAL LTD.
61c45bd11SMarcin Wojtas  * Copyright (c) 2017 Semihalf.
7373bbe25SRafal Jaworowski  * All rights reserved.
8373bbe25SRafal Jaworowski  *
9373bbe25SRafal Jaworowski  * Adapted and extended for Marvell SoCs by Semihalf.
10373bbe25SRafal Jaworowski  *
11373bbe25SRafal Jaworowski  * Redistribution and use in source and binary forms, with or without
12373bbe25SRafal Jaworowski  * modification, are permitted provided that the following conditions
13373bbe25SRafal Jaworowski  * are met:
14373bbe25SRafal Jaworowski  * 1. Redistributions of source code must retain the above copyright
15373bbe25SRafal Jaworowski  *    notice, this list of conditions and the following disclaimer.
16373bbe25SRafal Jaworowski  * 2. Redistributions in binary form must reproduce the above copyright
17373bbe25SRafal Jaworowski  *    notice, this list of conditions and the following disclaimer in the
18373bbe25SRafal Jaworowski  *    documentation and/or other materials provided with the distribution.
19373bbe25SRafal Jaworowski  *
20373bbe25SRafal Jaworowski  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21373bbe25SRafal Jaworowski  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22373bbe25SRafal Jaworowski  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23373bbe25SRafal Jaworowski  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24373bbe25SRafal Jaworowski  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25373bbe25SRafal Jaworowski  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26373bbe25SRafal Jaworowski  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27373bbe25SRafal Jaworowski  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28373bbe25SRafal Jaworowski  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29373bbe25SRafal Jaworowski  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30373bbe25SRafal Jaworowski  *
31373bbe25SRafal Jaworowski  * from: FreeBSD: //depot/projects/arm/src/sys/arm/xscale/pxa2x0/pxa2x0_gpio.c, rev 1
32373bbe25SRafal Jaworowski  */
33373bbe25SRafal Jaworowski 
34373bbe25SRafal Jaworowski #include <sys/param.h>
35373bbe25SRafal Jaworowski #include <sys/systm.h>
36373bbe25SRafal Jaworowski #include <sys/bus.h>
37373bbe25SRafal Jaworowski #include <sys/kernel.h>
38373bbe25SRafal Jaworowski #include <sys/lock.h>
39373bbe25SRafal Jaworowski #include <sys/interrupt.h>
40373bbe25SRafal Jaworowski #include <sys/module.h>
41373bbe25SRafal Jaworowski #include <sys/malloc.h>
42373bbe25SRafal Jaworowski #include <sys/mutex.h>
43373bbe25SRafal Jaworowski #include <sys/rman.h>
44373bbe25SRafal Jaworowski #include <sys/queue.h>
45373bbe25SRafal Jaworowski #include <sys/timetc.h>
461c45bd11SMarcin Wojtas #include <sys/callout.h>
471c45bd11SMarcin Wojtas #include <sys/gpio.h>
48373bbe25SRafal Jaworowski #include <machine/bus.h>
49373bbe25SRafal Jaworowski #include <machine/intr.h>
50373bbe25SRafal Jaworowski 
51ded9da68SMarcin Wojtas #include <dev/gpio/gpiobusvar.h>
52db5ef4fcSRafal Jaworowski #include <dev/ofw/ofw_bus.h>
53db5ef4fcSRafal Jaworowski #include <dev/ofw/ofw_bus_subr.h>
54db5ef4fcSRafal Jaworowski 
55373bbe25SRafal Jaworowski #include <arm/mv/mvvar.h>
56373bbe25SRafal Jaworowski #include <arm/mv/mvreg.h>
57373bbe25SRafal Jaworowski 
58ded9da68SMarcin Wojtas #include "gpio_if.h"
59ded9da68SMarcin Wojtas 
60373bbe25SRafal Jaworowski #define GPIO_MAX_INTR_COUNT	8
61373bbe25SRafal Jaworowski #define GPIO_PINS_PER_REG	32
62ded9da68SMarcin Wojtas #define GPIO_GENERIC_CAP	(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT |		\
63ded9da68SMarcin Wojtas 				GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL |	\
64ded9da68SMarcin Wojtas 				GPIO_PIN_TRISTATE | GPIO_PIN_PULLUP |		\
65ded9da68SMarcin Wojtas 				GPIO_PIN_PULLDOWN | GPIO_PIN_INVIN |		\
66ded9da68SMarcin Wojtas 				GPIO_PIN_INVOUT)
67373bbe25SRafal Jaworowski 
681c45bd11SMarcin Wojtas #define DEBOUNCE_CHECK_MS	1
691c45bd11SMarcin Wojtas #define DEBOUNCE_LO_HI_MS	2
701c45bd11SMarcin Wojtas #define DEBOUNCE_HI_LO_MS	2
711c45bd11SMarcin Wojtas #define DEBOUNCE_CHECK_TICKS	((hz / 1000) * DEBOUNCE_CHECK_MS)
721c45bd11SMarcin Wojtas 
73373bbe25SRafal Jaworowski struct mv_gpio_softc {
744f3a5b51SEmmanuel Vadot 	device_t		dev;
75ded9da68SMarcin Wojtas 	device_t		sc_busdev;
76ad2be10fSMarcin Wojtas 	struct resource	*	mem_res;
77ad2be10fSMarcin Wojtas 	int			mem_rid;
78ad2be10fSMarcin Wojtas 	struct resource	*	irq_res[GPIO_MAX_INTR_COUNT];
79ad2be10fSMarcin Wojtas 	int			irq_rid[GPIO_MAX_INTR_COUNT];
80edf9ef73SMarcin Wojtas 	struct intr_event *	gpio_events[MV_GPIO_MAX_NPINS];
81373bbe25SRafal Jaworowski 	void			*ih_cookie[GPIO_MAX_INTR_COUNT];
82373bbe25SRafal Jaworowski 	bus_space_tag_t		bst;
83373bbe25SRafal Jaworowski 	bus_space_handle_t	bsh;
844f3a5b51SEmmanuel Vadot 	uint32_t		offset;
851c45bd11SMarcin Wojtas 	struct mtx		mutex;
86373bbe25SRafal Jaworowski 	uint8_t			pin_num;	/* number of GPIO pins */
87373bbe25SRafal Jaworowski 	uint8_t			irq_num;	/* number of real IRQs occupied by GPIO controller */
88edf9ef73SMarcin Wojtas 	struct gpio_pin		gpio_setup[MV_GPIO_MAX_NPINS];
891c45bd11SMarcin Wojtas 
901c45bd11SMarcin Wojtas 	/* Used for debouncing. */
911c45bd11SMarcin Wojtas 	uint32_t		debounced_state_lo;
921c45bd11SMarcin Wojtas 	uint32_t		debounced_state_hi;
931c45bd11SMarcin Wojtas 	struct callout		**debounce_callouts;
941c45bd11SMarcin Wojtas 	int			*debounce_counters;
95373bbe25SRafal Jaworowski };
96373bbe25SRafal Jaworowski 
97edf9ef73SMarcin Wojtas struct mv_gpio_pindev {
98edf9ef73SMarcin Wojtas 	device_t dev;
99edf9ef73SMarcin Wojtas 	int pin;
100edf9ef73SMarcin Wojtas };
101373bbe25SRafal Jaworowski 
102373bbe25SRafal Jaworowski static int	mv_gpio_probe(device_t);
103373bbe25SRafal Jaworowski static int	mv_gpio_attach(device_t);
104edf9ef73SMarcin Wojtas static int	mv_gpio_intr(device_t, void *);
105373bbe25SRafal Jaworowski 
106edf9ef73SMarcin Wojtas static void	mv_gpio_double_edge_init(device_t, int);
1071c45bd11SMarcin Wojtas 
108edf9ef73SMarcin Wojtas static int	mv_gpio_debounce_setup(device_t, int);
109edf9ef73SMarcin Wojtas static int	mv_gpio_debounce_prepare(device_t, int);
110edf9ef73SMarcin Wojtas static int	mv_gpio_debounce_init(device_t, int);
111edf9ef73SMarcin Wojtas static void	mv_gpio_debounce_start(device_t, int);
112edf9ef73SMarcin Wojtas static void	mv_gpio_debounce(void *);
113edf9ef73SMarcin Wojtas static void	mv_gpio_debounced_state_set(device_t, int, uint8_t);
114edf9ef73SMarcin Wojtas static uint32_t	mv_gpio_debounced_state_get(device_t, int);
1151c45bd11SMarcin Wojtas 
116edf9ef73SMarcin Wojtas static void	mv_gpio_exec_intr_handlers(device_t, uint32_t, int);
117edf9ef73SMarcin Wojtas static void	mv_gpio_intr_handler(device_t, int);
118edf9ef73SMarcin Wojtas static uint32_t	mv_gpio_reg_read(device_t, uint32_t);
119edf9ef73SMarcin Wojtas static void	mv_gpio_reg_write(device_t, uint32_t, uint32_t);
120edf9ef73SMarcin Wojtas static void	mv_gpio_reg_set(device_t, uint32_t, uint32_t);
121edf9ef73SMarcin Wojtas static void	mv_gpio_reg_clear(device_t, uint32_t, uint32_t);
122373bbe25SRafal Jaworowski 
123edf9ef73SMarcin Wojtas static void	mv_gpio_blink(device_t, uint32_t, uint8_t);
124edf9ef73SMarcin Wojtas static void	mv_gpio_polarity(device_t, uint32_t, uint8_t, uint8_t);
125edf9ef73SMarcin Wojtas static void	mv_gpio_level(device_t, uint32_t, uint8_t);
126edf9ef73SMarcin Wojtas static void	mv_gpio_edge(device_t, uint32_t, uint8_t);
127edf9ef73SMarcin Wojtas static void	mv_gpio_out_en(device_t, uint32_t, uint8_t);
128edf9ef73SMarcin Wojtas static void	mv_gpio_int_ack(struct mv_gpio_pindev *);
129edf9ef73SMarcin Wojtas static void	mv_gpio_value_set(device_t, uint32_t, uint8_t);
130edf9ef73SMarcin Wojtas static uint32_t	mv_gpio_value_get(device_t, uint32_t, uint8_t);
1311c45bd11SMarcin Wojtas 
132edf9ef73SMarcin Wojtas static void	mv_gpio_intr_mask(struct mv_gpio_pindev *);
133edf9ef73SMarcin Wojtas static void	mv_gpio_intr_unmask(struct mv_gpio_pindev *);
134ad2be10fSMarcin Wojtas 
135edf9ef73SMarcin Wojtas void mv_gpio_finish_intrhandler(struct mv_gpio_pindev *);
136edf9ef73SMarcin Wojtas int mv_gpio_setup_intrhandler(device_t, const char *,
137edf9ef73SMarcin Wojtas     driver_filter_t *, void (*)(void *), void *,
138edf9ef73SMarcin Wojtas     int, int, void **);
139edf9ef73SMarcin Wojtas int mv_gpio_configure(device_t, uint32_t, uint32_t, uint32_t);
140edf9ef73SMarcin Wojtas void mv_gpio_out(device_t, uint32_t, uint8_t, uint8_t);
141edf9ef73SMarcin Wojtas uint8_t mv_gpio_in(device_t, uint32_t);
142ad2be10fSMarcin Wojtas 
143ded9da68SMarcin Wojtas /*
144ded9da68SMarcin Wojtas  * GPIO interface
145ded9da68SMarcin Wojtas  */
146ded9da68SMarcin Wojtas static device_t mv_gpio_get_bus(device_t);
147ded9da68SMarcin Wojtas static int mv_gpio_pin_max(device_t, int *);
148ded9da68SMarcin Wojtas static int mv_gpio_pin_getcaps(device_t, uint32_t, uint32_t *);
149ded9da68SMarcin Wojtas static int mv_gpio_pin_getflags(device_t, uint32_t, uint32_t *);
150ded9da68SMarcin Wojtas static int mv_gpio_pin_getname(device_t, uint32_t, char *);
151ded9da68SMarcin Wojtas static int mv_gpio_pin_setflags(device_t, uint32_t, uint32_t);
152ded9da68SMarcin Wojtas static int mv_gpio_pin_set(device_t, uint32_t, unsigned int);
153ded9da68SMarcin Wojtas static int mv_gpio_pin_get(device_t, uint32_t, unsigned int *);
154ded9da68SMarcin Wojtas static int mv_gpio_pin_toggle(device_t, uint32_t);
1552a94dbf5SMarcin Wojtas static int mv_gpio_map_gpios(device_t, phandle_t, phandle_t,
1562a94dbf5SMarcin Wojtas     int, pcell_t *, uint32_t *, uint32_t *);
157ded9da68SMarcin Wojtas 
158edf9ef73SMarcin Wojtas #define MV_GPIO_LOCK()		mtx_lock_spin(&sc->mutex)
159edf9ef73SMarcin Wojtas #define MV_GPIO_UNLOCK()	mtx_unlock_spin(&sc->mutex)
160edf9ef73SMarcin Wojtas #define MV_GPIO_ASSERT_LOCKED()	mtx_assert(&sc->mutex, MA_OWNED)
161373bbe25SRafal Jaworowski 
162373bbe25SRafal Jaworowski static device_method_t mv_gpio_methods[] = {
163373bbe25SRafal Jaworowski 	DEVMETHOD(device_probe,		mv_gpio_probe),
164373bbe25SRafal Jaworowski 	DEVMETHOD(device_attach,	mv_gpio_attach),
165ded9da68SMarcin Wojtas 
166ded9da68SMarcin Wojtas 	/* GPIO protocol */
167ded9da68SMarcin Wojtas 	DEVMETHOD(gpio_get_bus,		mv_gpio_get_bus),
168ded9da68SMarcin Wojtas 	DEVMETHOD(gpio_pin_max,		mv_gpio_pin_max),
169ded9da68SMarcin Wojtas 	DEVMETHOD(gpio_pin_getname,	mv_gpio_pin_getname),
170ded9da68SMarcin Wojtas 	DEVMETHOD(gpio_pin_getflags,	mv_gpio_pin_getflags),
171ded9da68SMarcin Wojtas 	DEVMETHOD(gpio_pin_getcaps,	mv_gpio_pin_getcaps),
172ded9da68SMarcin Wojtas 	DEVMETHOD(gpio_pin_setflags,	mv_gpio_pin_setflags),
173ded9da68SMarcin Wojtas 	DEVMETHOD(gpio_pin_get,		mv_gpio_pin_get),
174ded9da68SMarcin Wojtas 	DEVMETHOD(gpio_pin_set,		mv_gpio_pin_set),
175ded9da68SMarcin Wojtas 	DEVMETHOD(gpio_pin_toggle,	mv_gpio_pin_toggle),
1762a94dbf5SMarcin Wojtas 	DEVMETHOD(gpio_map_gpios,	mv_gpio_map_gpios),
177ded9da68SMarcin Wojtas 
178ded9da68SMarcin Wojtas 	DEVMETHOD_END
179373bbe25SRafal Jaworowski };
180373bbe25SRafal Jaworowski 
181373bbe25SRafal Jaworowski static driver_t mv_gpio_driver = {
182373bbe25SRafal Jaworowski 	"gpio",
183373bbe25SRafal Jaworowski 	mv_gpio_methods,
184373bbe25SRafal Jaworowski 	sizeof(struct mv_gpio_softc),
185373bbe25SRafal Jaworowski };
186373bbe25SRafal Jaworowski 
187a3b866cbSJohn Baldwin EARLY_DRIVER_MODULE(mv_gpio, simplebus, mv_gpio_driver, 0, 0,
188e5ff483eSEmmanuel Vadot     BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LAST);
189db5ef4fcSRafal Jaworowski 
1904f3a5b51SEmmanuel Vadot struct ofw_compat_data compat_data[] = {
1914f3a5b51SEmmanuel Vadot 	{ "mrvl,gpio", 1 },
1924f3a5b51SEmmanuel Vadot 	{ "marvell,orion-gpio", 1 },
193ded9da68SMarcin Wojtas 	{ NULL, 0 }
194db5ef4fcSRafal Jaworowski };
195373bbe25SRafal Jaworowski 
196373bbe25SRafal Jaworowski static int
mv_gpio_probe(device_t dev)197373bbe25SRafal Jaworowski mv_gpio_probe(device_t dev)
198373bbe25SRafal Jaworowski {
199add35ed5SIan Lepore 	if (!ofw_bus_status_okay(dev))
200add35ed5SIan Lepore 		return (ENXIO);
201add35ed5SIan Lepore 
2024f3a5b51SEmmanuel Vadot 	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
203db5ef4fcSRafal Jaworowski 		return (ENXIO);
204db5ef4fcSRafal Jaworowski 
205373bbe25SRafal Jaworowski 	device_set_desc(dev, "Marvell Integrated GPIO Controller");
206373bbe25SRafal Jaworowski 	return (0);
207373bbe25SRafal Jaworowski }
208373bbe25SRafal Jaworowski 
209373bbe25SRafal Jaworowski static int
mv_gpio_setup_interrupts(struct mv_gpio_softc * sc,phandle_t node)2104f3a5b51SEmmanuel Vadot mv_gpio_setup_interrupts(struct mv_gpio_softc *sc, phandle_t node)
211373bbe25SRafal Jaworowski {
212ad2be10fSMarcin Wojtas 	phandle_t iparent;
2134f3a5b51SEmmanuel Vadot 	pcell_t irq_cells;
2144f3a5b51SEmmanuel Vadot 	int i, size;
215ad2be10fSMarcin Wojtas 
216ad2be10fSMarcin Wojtas 	/* Find root interrupt controller */
2174f3a5b51SEmmanuel Vadot 	iparent = ofw_bus_find_iparent(node);
218ad2be10fSMarcin Wojtas 	if (iparent == 0) {
2194f3a5b51SEmmanuel Vadot 		device_printf(sc->dev, "No interrupt-parrent found. "
220ad2be10fSMarcin Wojtas 				"Error in DTB\n");
221ad2be10fSMarcin Wojtas 		return (ENXIO);
222ad2be10fSMarcin Wojtas 	} else {
223ad2be10fSMarcin Wojtas 		/* While at parent - store interrupt cells prop */
224ad2be10fSMarcin Wojtas 		if (OF_searchencprop(OF_node_from_xref(iparent),
225ad2be10fSMarcin Wojtas 		    "#interrupt-cells", &irq_cells, sizeof(irq_cells)) == -1) {
2264f3a5b51SEmmanuel Vadot 			device_printf(sc->dev, "DTB: Missing #interrupt-cells "
227ad2be10fSMarcin Wojtas 			    "property in interrupt parent node\n");
228ad2be10fSMarcin Wojtas 			return (ENXIO);
229ad2be10fSMarcin Wojtas 		}
230ad2be10fSMarcin Wojtas 	}
231ad2be10fSMarcin Wojtas 
2324f3a5b51SEmmanuel Vadot 	size = OF_getproplen(node, "interrupts");
233ad2be10fSMarcin Wojtas 	if (size != -1) {
234ad2be10fSMarcin Wojtas 		size = size / sizeof(pcell_t);
235ad2be10fSMarcin Wojtas 		size = size / irq_cells;
236ad2be10fSMarcin Wojtas 		sc->irq_num = size;
2374f3a5b51SEmmanuel Vadot 		device_printf(sc->dev, "%d IRQs available\n", sc->irq_num);
238ad2be10fSMarcin Wojtas 	} else {
2394f3a5b51SEmmanuel Vadot 		device_printf(sc->dev, "ERROR: no interrupts entry found!\n");
240373bbe25SRafal Jaworowski 		return (ENXIO);
241373bbe25SRafal Jaworowski 	}
242373bbe25SRafal Jaworowski 
2434f3a5b51SEmmanuel Vadot 	for (i = 0; i < sc->irq_num; i++) {
2444f3a5b51SEmmanuel Vadot 		sc->irq_rid[i] = i;
2454f3a5b51SEmmanuel Vadot 		sc->irq_res[i] = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ,
2464f3a5b51SEmmanuel Vadot 			&sc->irq_rid[i], RF_ACTIVE);
2474f3a5b51SEmmanuel Vadot 		if (!sc->irq_res[i]) {
2484f3a5b51SEmmanuel Vadot 			mtx_destroy(&sc->mutex);
2494f3a5b51SEmmanuel Vadot 			device_printf(sc->dev,
2504f3a5b51SEmmanuel Vadot 			    "could not allocate gpio%d interrupt\n", i+1);
2514f3a5b51SEmmanuel Vadot 			return (ENXIO);
2524f3a5b51SEmmanuel Vadot 		}
2534f3a5b51SEmmanuel Vadot 	}
2544f3a5b51SEmmanuel Vadot 
2554f3a5b51SEmmanuel Vadot 	device_printf(sc->dev, "Disable interrupts (offset = %x + EDGE(0x18)\n", sc->offset);
2564f3a5b51SEmmanuel Vadot 	/* Disable all interrupts */
2574f3a5b51SEmmanuel Vadot 	bus_space_write_4(sc->bst, sc->bsh, sc->offset + GPIO_INT_EDGE_MASK, 0);
2584f3a5b51SEmmanuel Vadot 	device_printf(sc->dev, "Disable interrupts (offset = %x + LEV(0x1C))\n", sc->offset);
2594f3a5b51SEmmanuel Vadot 	bus_space_write_4(sc->bst, sc->bsh, sc->offset + GPIO_INT_LEV_MASK, 0);
2604f3a5b51SEmmanuel Vadot 
2614f3a5b51SEmmanuel Vadot 	for (i = 0; i < sc->irq_num; i++) {
2624f3a5b51SEmmanuel Vadot 		device_printf(sc->dev, "Setup intr %d\n", i);
2634f3a5b51SEmmanuel Vadot 		if (bus_setup_intr(sc->dev, sc->irq_res[i],
2644f3a5b51SEmmanuel Vadot 		    INTR_TYPE_MISC,
2654f3a5b51SEmmanuel Vadot 		    (driver_filter_t *)mv_gpio_intr, NULL,
2664f3a5b51SEmmanuel Vadot 		    sc, &sc->ih_cookie[i]) != 0) {
2674f3a5b51SEmmanuel Vadot 			mtx_destroy(&sc->mutex);
2684f3a5b51SEmmanuel Vadot 			bus_release_resource(sc->dev, SYS_RES_IRQ,
2694f3a5b51SEmmanuel Vadot 				sc->irq_rid[i], sc->irq_res[i]);
2704f3a5b51SEmmanuel Vadot 			device_printf(sc->dev, "could not set up intr %d\n", i);
2714f3a5b51SEmmanuel Vadot 			return (ENXIO);
2724f3a5b51SEmmanuel Vadot 		}
2734f3a5b51SEmmanuel Vadot 	}
2744f3a5b51SEmmanuel Vadot 
2754f3a5b51SEmmanuel Vadot 	/* Clear interrupt status. */
2764f3a5b51SEmmanuel Vadot 	device_printf(sc->dev, "Clear int status (offset = %x)\n", sc->offset);
2774f3a5b51SEmmanuel Vadot 	bus_space_write_4(sc->bst, sc->bsh, sc->offset + GPIO_INT_CAUSE, 0);
2784f3a5b51SEmmanuel Vadot 
2791c45bd11SMarcin Wojtas 	sc->debounce_callouts = (struct callout **)malloc(sc->pin_num *
2801c45bd11SMarcin Wojtas 	    sizeof(struct callout *), M_DEVBUF, M_WAITOK | M_ZERO);
2811c45bd11SMarcin Wojtas 	if (sc->debounce_callouts == NULL)
2821c45bd11SMarcin Wojtas 		return (ENOMEM);
2831c45bd11SMarcin Wojtas 
2841c45bd11SMarcin Wojtas 	sc->debounce_counters = (int *)malloc(sc->pin_num * sizeof(int),
2851c45bd11SMarcin Wojtas 	    M_DEVBUF, M_WAITOK);
2861c45bd11SMarcin Wojtas 	if (sc->debounce_counters == NULL)
2871c45bd11SMarcin Wojtas 		return (ENOMEM);
2881c45bd11SMarcin Wojtas 
2894f3a5b51SEmmanuel Vadot 	return (0);
2904f3a5b51SEmmanuel Vadot }
2914f3a5b51SEmmanuel Vadot 
2924f3a5b51SEmmanuel Vadot static int
mv_gpio_attach(device_t dev)2934f3a5b51SEmmanuel Vadot mv_gpio_attach(device_t dev)
2944f3a5b51SEmmanuel Vadot {
2954f3a5b51SEmmanuel Vadot 	int i, rv;
2964f3a5b51SEmmanuel Vadot 	struct mv_gpio_softc *sc;
2974f3a5b51SEmmanuel Vadot 	phandle_t node;
2984f3a5b51SEmmanuel Vadot 	pcell_t pincnt = 0;
2994f3a5b51SEmmanuel Vadot 
3004f3a5b51SEmmanuel Vadot 	sc = (struct mv_gpio_softc *)device_get_softc(dev);
3014f3a5b51SEmmanuel Vadot 	if (sc == NULL)
3024f3a5b51SEmmanuel Vadot 		return (ENXIO);
3034f3a5b51SEmmanuel Vadot 
3044f3a5b51SEmmanuel Vadot 	node = ofw_bus_get_node(dev);
3054f3a5b51SEmmanuel Vadot 	sc->dev = dev;
3064f3a5b51SEmmanuel Vadot 
3074f3a5b51SEmmanuel Vadot 	if (OF_getencprop(node, "pin-count", &pincnt, sizeof(pcell_t)) >= 0 ||
3084f3a5b51SEmmanuel Vadot 	    OF_getencprop(node, "ngpios", &pincnt, sizeof(pcell_t)) >= 0) {
3094f3a5b51SEmmanuel Vadot 		sc->pin_num = MIN(pincnt, MV_GPIO_MAX_NPINS);
3104f3a5b51SEmmanuel Vadot 		if (bootverbose)
3114f3a5b51SEmmanuel Vadot 			device_printf(dev, "%d pins available\n", sc->pin_num);
3124f3a5b51SEmmanuel Vadot 	} else {
3134f3a5b51SEmmanuel Vadot 		device_printf(dev, "ERROR: no pin-count or ngpios entry found!\n");
3144f3a5b51SEmmanuel Vadot 		return (ENXIO);
3154f3a5b51SEmmanuel Vadot 	}
3164f3a5b51SEmmanuel Vadot 
3174f3a5b51SEmmanuel Vadot 	if (OF_getencprop(node, "offset", &sc->offset, sizeof(sc->offset)) == -1)
3184f3a5b51SEmmanuel Vadot 		sc->offset = 0;
3194f3a5b51SEmmanuel Vadot 
3204f3a5b51SEmmanuel Vadot 	/* Assign generic capabilities to every gpio pin */
3214f3a5b51SEmmanuel Vadot 	for(i = 0; i < sc->pin_num; i++)
3224f3a5b51SEmmanuel Vadot 		sc->gpio_setup[i].gp_caps = GPIO_GENERIC_CAP;
3234f3a5b51SEmmanuel Vadot 
3241c45bd11SMarcin Wojtas 	mtx_init(&sc->mutex, device_get_nameunit(dev), NULL, MTX_SPIN);
3251c45bd11SMarcin Wojtas 
326ad2be10fSMarcin Wojtas 	sc->mem_rid = 0;
327ad2be10fSMarcin Wojtas 	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid,
3284f3a5b51SEmmanuel Vadot 		 RF_ACTIVE | RF_SHAREABLE );
329ad2be10fSMarcin Wojtas 
330ad2be10fSMarcin Wojtas 	if (!sc->mem_res) {
3311c45bd11SMarcin Wojtas 		mtx_destroy(&sc->mutex);
332ad2be10fSMarcin Wojtas 		device_printf(dev, "could not allocate memory window\n");
333373bbe25SRafal Jaworowski 		return (ENXIO);
334373bbe25SRafal Jaworowski 	}
335373bbe25SRafal Jaworowski 
336ad2be10fSMarcin Wojtas 	sc->bst = rman_get_bustag(sc->mem_res);
337ad2be10fSMarcin Wojtas 	sc->bsh = rman_get_bushandle(sc->mem_res);
338ad2be10fSMarcin Wojtas 
3394f3a5b51SEmmanuel Vadot 	rv = mv_gpio_setup_interrupts(sc, node);
3404f3a5b51SEmmanuel Vadot 	if (rv != 0)
3414f3a5b51SEmmanuel Vadot 		return (rv);
3421c45bd11SMarcin Wojtas 
343ded9da68SMarcin Wojtas 	sc->sc_busdev = gpiobus_attach_bus(dev);
344ded9da68SMarcin Wojtas 	if (sc->sc_busdev == NULL) {
345ded9da68SMarcin Wojtas 		mtx_destroy(&sc->mutex);
346ded9da68SMarcin Wojtas 		bus_release_resource(dev, SYS_RES_IRQ,
347ded9da68SMarcin Wojtas 			sc->irq_rid[i], sc->irq_res[i]);
348ded9da68SMarcin Wojtas 		return (ENXIO);
349ded9da68SMarcin Wojtas 	}
350edf9ef73SMarcin Wojtas 
3511c45bd11SMarcin Wojtas 	return (0);
352373bbe25SRafal Jaworowski }
353373bbe25SRafal Jaworowski 
35431e55059SJohn Baldwin static int
mv_gpio_intr(device_t dev,void * arg)355edf9ef73SMarcin Wojtas mv_gpio_intr(device_t dev, void *arg)
356373bbe25SRafal Jaworowski {
357373bbe25SRafal Jaworowski 	uint32_t int_cause, gpio_val;
358edf9ef73SMarcin Wojtas 	struct mv_gpio_softc *sc;
359edf9ef73SMarcin Wojtas 	sc = (struct mv_gpio_softc *)device_get_softc(dev);
360373bbe25SRafal Jaworowski 
3611c45bd11SMarcin Wojtas 	MV_GPIO_LOCK();
3621c45bd11SMarcin Wojtas 
3631c45bd11SMarcin Wojtas 	/*
3641c45bd11SMarcin Wojtas 	 * According to documentation, edge sensitive interrupts are asserted
3651c45bd11SMarcin Wojtas 	 * when unmasked GPIO_INT_CAUSE register bits are set.
3661c45bd11SMarcin Wojtas 	 */
367edf9ef73SMarcin Wojtas 	int_cause = mv_gpio_reg_read(dev, GPIO_INT_CAUSE);
368edf9ef73SMarcin Wojtas 	int_cause &= mv_gpio_reg_read(dev, GPIO_INT_EDGE_MASK);
3691c45bd11SMarcin Wojtas 
3701c45bd11SMarcin Wojtas 	/*
3711c45bd11SMarcin Wojtas 	 * Level sensitive interrupts are asserted when unmasked GPIO_DATA_IN
3721c45bd11SMarcin Wojtas 	 * register bits are set.
3731c45bd11SMarcin Wojtas 	 */
374edf9ef73SMarcin Wojtas 	gpio_val = mv_gpio_reg_read(dev, GPIO_DATA_IN);
375edf9ef73SMarcin Wojtas 	gpio_val &= mv_gpio_reg_read(dev, GPIO_INT_LEV_MASK);
3761c45bd11SMarcin Wojtas 
377edf9ef73SMarcin Wojtas 	mv_gpio_exec_intr_handlers(dev, int_cause | gpio_val, 0);
3781c45bd11SMarcin Wojtas 
3791c45bd11SMarcin Wojtas 	MV_GPIO_UNLOCK();
38031e55059SJohn Baldwin 
38131e55059SJohn Baldwin 	return (FILTER_HANDLED);
382373bbe25SRafal Jaworowski }
383373bbe25SRafal Jaworowski 
384373bbe25SRafal Jaworowski /*
385373bbe25SRafal Jaworowski  * GPIO interrupt handling
386373bbe25SRafal Jaworowski  */
387373bbe25SRafal Jaworowski 
388edf9ef73SMarcin Wojtas void
mv_gpio_finish_intrhandler(struct mv_gpio_pindev * s)389edf9ef73SMarcin Wojtas mv_gpio_finish_intrhandler(struct mv_gpio_pindev *s)
390edf9ef73SMarcin Wojtas {
391edf9ef73SMarcin Wojtas 	/* When we acheive full interrupt support
392edf9ef73SMarcin Wojtas 	 * This function will be opposite to
393edf9ef73SMarcin Wojtas 	 * mv_gpio_setup_intrhandler
394edf9ef73SMarcin Wojtas 	 */
395edf9ef73SMarcin Wojtas 
396edf9ef73SMarcin Wojtas 	/* Now it exists only to remind that
397edf9ef73SMarcin Wojtas 	 * there should be place to free mv_gpio_pindev
398edf9ef73SMarcin Wojtas 	 * allocated by mv_gpio_setup_intrhandler
399edf9ef73SMarcin Wojtas 	 */
400edf9ef73SMarcin Wojtas 	free(s, M_DEVBUF);
401edf9ef73SMarcin Wojtas }
402373bbe25SRafal Jaworowski 
403373bbe25SRafal Jaworowski int
mv_gpio_setup_intrhandler(device_t dev,const char * name,driver_filter_t * filt,void (* hand)(void *),void * arg,int pin,int flags,void ** cookiep)404edf9ef73SMarcin Wojtas mv_gpio_setup_intrhandler(device_t dev, const char *name, driver_filter_t *filt,
405373bbe25SRafal Jaworowski     void (*hand)(void *), void *arg, int pin, int flags, void **cookiep)
406373bbe25SRafal Jaworowski {
407373bbe25SRafal Jaworowski 	struct	intr_event *event;
408373bbe25SRafal Jaworowski 	int	error;
409edf9ef73SMarcin Wojtas 	struct mv_gpio_pindev *s;
410edf9ef73SMarcin Wojtas 	struct mv_gpio_softc *sc;
411edf9ef73SMarcin Wojtas 	sc = (struct mv_gpio_softc *)device_get_softc(dev);
412edf9ef73SMarcin Wojtas 	s = malloc(sizeof(struct mv_gpio_pindev), M_DEVBUF, M_NOWAIT | M_ZERO);
413373bbe25SRafal Jaworowski 
414edf9ef73SMarcin Wojtas 	if (pin < 0 || pin >= sc->pin_num)
415373bbe25SRafal Jaworowski 		return (ENXIO);
416edf9ef73SMarcin Wojtas 	event = sc->gpio_events[pin];
417373bbe25SRafal Jaworowski 	if (event == NULL) {
4181c45bd11SMarcin Wojtas 		MV_GPIO_LOCK();
419edf9ef73SMarcin Wojtas 		if (sc->gpio_setup[pin].gp_flags & MV_GPIO_IN_DEBOUNCE) {
420edf9ef73SMarcin Wojtas 			error = mv_gpio_debounce_init(dev, pin);
4211c45bd11SMarcin Wojtas 			if (error != 0) {
4221c45bd11SMarcin Wojtas 				MV_GPIO_UNLOCK();
4231c45bd11SMarcin Wojtas 				return (error);
4241c45bd11SMarcin Wojtas 			}
425edf9ef73SMarcin Wojtas 		} else if (sc->gpio_setup[pin].gp_flags & MV_GPIO_IN_IRQ_DOUBLE_EDGE)
426edf9ef73SMarcin Wojtas 			mv_gpio_double_edge_init(dev, pin);
4271c45bd11SMarcin Wojtas 		MV_GPIO_UNLOCK();
428edf9ef73SMarcin Wojtas 		error = intr_event_create(&event, (void *)s, 0, pin,
429373bbe25SRafal Jaworowski 		    (void (*)(void *))mv_gpio_intr_mask,
430373bbe25SRafal Jaworowski 		    (void (*)(void *))mv_gpio_intr_unmask,
431373bbe25SRafal Jaworowski 		    (void (*)(void *))mv_gpio_int_ack,
432373bbe25SRafal Jaworowski 		    NULL,
433373bbe25SRafal Jaworowski 		    "gpio%d:", pin);
434373bbe25SRafal Jaworowski 		if (error != 0)
435373bbe25SRafal Jaworowski 			return (error);
436edf9ef73SMarcin Wojtas 		sc->gpio_events[pin] = event;
437373bbe25SRafal Jaworowski 	}
438373bbe25SRafal Jaworowski 
439aba47c3fSRafal Jaworowski 	intr_event_add_handler(event, name, filt, hand, arg,
440aba47c3fSRafal Jaworowski 	    intr_priority(flags), flags, cookiep);
441373bbe25SRafal Jaworowski 	return (0);
442373bbe25SRafal Jaworowski }
443373bbe25SRafal Jaworowski 
444edf9ef73SMarcin Wojtas static void
mv_gpio_intr_mask(struct mv_gpio_pindev * s)445edf9ef73SMarcin Wojtas mv_gpio_intr_mask(struct mv_gpio_pindev *s)
446373bbe25SRafal Jaworowski {
447edf9ef73SMarcin Wojtas 	struct mv_gpio_softc *sc;
448edf9ef73SMarcin Wojtas 	sc = (struct mv_gpio_softc *)device_get_softc(s->dev);
449373bbe25SRafal Jaworowski 
450edf9ef73SMarcin Wojtas 	if (s->pin >= sc->pin_num)
451373bbe25SRafal Jaworowski 		return;
452373bbe25SRafal Jaworowski 
4531c45bd11SMarcin Wojtas 	MV_GPIO_LOCK();
4541c45bd11SMarcin Wojtas 
455edf9ef73SMarcin Wojtas 	if (sc->gpio_setup[s->pin].gp_flags & (MV_GPIO_IN_IRQ_EDGE |
456edf9ef73SMarcin Wojtas 	    MV_GPIO_IN_IRQ_DOUBLE_EDGE))
457edf9ef73SMarcin Wojtas 		mv_gpio_edge(s->dev, s->pin, 0);
458373bbe25SRafal Jaworowski 	else
459edf9ef73SMarcin Wojtas 		mv_gpio_level(s->dev, s->pin, 0);
4601c45bd11SMarcin Wojtas 
4611c45bd11SMarcin Wojtas 	/*
4621c45bd11SMarcin Wojtas 	 * The interrupt has to be acknowledged before scheduling an interrupt
4631c45bd11SMarcin Wojtas 	 * thread. This way we allow for interrupt source to trigger again
4641c45bd11SMarcin Wojtas 	 * (which can happen with shared IRQs e.g. PCI) while processing the
4651c45bd11SMarcin Wojtas 	 * current event.
4661c45bd11SMarcin Wojtas 	 */
467edf9ef73SMarcin Wojtas 	mv_gpio_int_ack(s);
4681c45bd11SMarcin Wojtas 
4691c45bd11SMarcin Wojtas 	MV_GPIO_UNLOCK();
470edf9ef73SMarcin Wojtas 
471edf9ef73SMarcin Wojtas 	return;
472373bbe25SRafal Jaworowski }
473373bbe25SRafal Jaworowski 
474edf9ef73SMarcin Wojtas static void
mv_gpio_intr_unmask(struct mv_gpio_pindev * s)475edf9ef73SMarcin Wojtas mv_gpio_intr_unmask(struct mv_gpio_pindev *s)
476373bbe25SRafal Jaworowski {
477edf9ef73SMarcin Wojtas 	struct mv_gpio_softc *sc;
478edf9ef73SMarcin Wojtas 	sc = (struct mv_gpio_softc *)device_get_softc(s->dev);
479373bbe25SRafal Jaworowski 
480edf9ef73SMarcin Wojtas 	if (s->pin >= sc->pin_num)
481373bbe25SRafal Jaworowski 		return;
482373bbe25SRafal Jaworowski 
4831c45bd11SMarcin Wojtas 	MV_GPIO_LOCK();
4841c45bd11SMarcin Wojtas 
485edf9ef73SMarcin Wojtas 	if (sc->gpio_setup[s->pin].gp_flags & (MV_GPIO_IN_IRQ_EDGE |
486edf9ef73SMarcin Wojtas 	    MV_GPIO_IN_IRQ_DOUBLE_EDGE))
487edf9ef73SMarcin Wojtas 		mv_gpio_edge(s->dev, s->pin, 1);
488373bbe25SRafal Jaworowski 	else
489edf9ef73SMarcin Wojtas 		mv_gpio_level(s->dev, s->pin, 1);
4901c45bd11SMarcin Wojtas 
4911c45bd11SMarcin Wojtas 	MV_GPIO_UNLOCK();
492edf9ef73SMarcin Wojtas 
493edf9ef73SMarcin Wojtas 	return;
4941c45bd11SMarcin Wojtas }
4951c45bd11SMarcin Wojtas 
4961c45bd11SMarcin Wojtas static void
mv_gpio_exec_intr_handlers(device_t dev,uint32_t status,int high)497edf9ef73SMarcin Wojtas mv_gpio_exec_intr_handlers(device_t dev, uint32_t status, int high)
4981c45bd11SMarcin Wojtas {
4991c45bd11SMarcin Wojtas 	int i, pin;
500edf9ef73SMarcin Wojtas 	struct mv_gpio_softc *sc;
501edf9ef73SMarcin Wojtas 	sc = (struct mv_gpio_softc *)device_get_softc(dev);
5021c45bd11SMarcin Wojtas 
5031c45bd11SMarcin Wojtas 	MV_GPIO_ASSERT_LOCKED();
5041c45bd11SMarcin Wojtas 
5051c45bd11SMarcin Wojtas 	i = 0;
5061c45bd11SMarcin Wojtas 	while (status != 0) {
5071c45bd11SMarcin Wojtas 		if (status & 1) {
5081c45bd11SMarcin Wojtas 			pin = (high ? (i + GPIO_PINS_PER_REG) : i);
509edf9ef73SMarcin Wojtas 			if (sc->gpio_setup[pin].gp_flags & MV_GPIO_IN_DEBOUNCE)
510edf9ef73SMarcin Wojtas 				mv_gpio_debounce_start(dev, pin);
511edf9ef73SMarcin Wojtas 			else if (sc->gpio_setup[pin].gp_flags & MV_GPIO_IN_IRQ_DOUBLE_EDGE) {
512edf9ef73SMarcin Wojtas 				mv_gpio_polarity(dev, pin, 0, 1);
513edf9ef73SMarcin Wojtas 				mv_gpio_intr_handler(dev, pin);
5141c45bd11SMarcin Wojtas 			} else
515edf9ef73SMarcin Wojtas 				mv_gpio_intr_handler(dev, pin);
5161c45bd11SMarcin Wojtas 		}
5171c45bd11SMarcin Wojtas 		status >>= 1;
5181c45bd11SMarcin Wojtas 		i++;
5191c45bd11SMarcin Wojtas 	}
520373bbe25SRafal Jaworowski }
521373bbe25SRafal Jaworowski 
522373bbe25SRafal Jaworowski static void
mv_gpio_intr_handler(device_t dev,int pin)523edf9ef73SMarcin Wojtas mv_gpio_intr_handler(device_t dev, int pin)
524373bbe25SRafal Jaworowski {
525ad2be10fSMarcin Wojtas 	struct intr_irqsrc isrc;
526edf9ef73SMarcin Wojtas 	struct mv_gpio_softc *sc;
527edf9ef73SMarcin Wojtas 	sc = (struct mv_gpio_softc *)device_get_softc(dev);
528373bbe25SRafal Jaworowski 
5291c45bd11SMarcin Wojtas 	MV_GPIO_ASSERT_LOCKED();
5301c45bd11SMarcin Wojtas 
531ad2be10fSMarcin Wojtas #ifdef INTR_SOLO
532ad2be10fSMarcin Wojtas 	isrc.isrc_filter = NULL;
533ad2be10fSMarcin Wojtas #endif
534edf9ef73SMarcin Wojtas 	isrc.isrc_event = sc->gpio_events[pin];
535ad2be10fSMarcin Wojtas 
53625594739SAndriy Gapon 	if (isrc.isrc_event == NULL ||
53725594739SAndriy Gapon 	    CK_SLIST_EMPTY(&isrc.isrc_event->ie_handlers))
538373bbe25SRafal Jaworowski 		return;
539373bbe25SRafal Jaworowski 
540ad2be10fSMarcin Wojtas 	intr_isrc_dispatch(&isrc, NULL);
541373bbe25SRafal Jaworowski }
542373bbe25SRafal Jaworowski 
5431c45bd11SMarcin Wojtas int
mv_gpio_configure(device_t dev,uint32_t pin,uint32_t flags,uint32_t mask)544edf9ef73SMarcin Wojtas mv_gpio_configure(device_t dev, uint32_t pin, uint32_t flags, uint32_t mask)
545373bbe25SRafal Jaworowski {
5461c45bd11SMarcin Wojtas 	int error;
547edf9ef73SMarcin Wojtas 	struct mv_gpio_softc *sc;
548edf9ef73SMarcin Wojtas 	sc = (struct mv_gpio_softc *)device_get_softc(dev);
549edf9ef73SMarcin Wojtas 	error = 0;
550373bbe25SRafal Jaworowski 
551edf9ef73SMarcin Wojtas 	if (pin >= sc->pin_num)
552373bbe25SRafal Jaworowski 		return (EINVAL);
553373bbe25SRafal Jaworowski 
5541c45bd11SMarcin Wojtas 	/* check flags consistency */
5551c45bd11SMarcin Wojtas 	if (((flags & mask) & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) ==
5561c45bd11SMarcin Wojtas 	    (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT))
5571c45bd11SMarcin Wojtas 		return (EINVAL);
558373bbe25SRafal Jaworowski 
5591c45bd11SMarcin Wojtas 	if (mask & MV_GPIO_IN_DEBOUNCE) {
5604f3a5b51SEmmanuel Vadot 		if (sc->irq_num == 0)
5614f3a5b51SEmmanuel Vadot 			return (EINVAL);
562edf9ef73SMarcin Wojtas 		error = mv_gpio_debounce_prepare(dev, pin);
5631c45bd11SMarcin Wojtas 		if (error != 0)
5641c45bd11SMarcin Wojtas 			return (error);
5651c45bd11SMarcin Wojtas 	}
5661c45bd11SMarcin Wojtas 
5671c45bd11SMarcin Wojtas 	MV_GPIO_LOCK();
5681c45bd11SMarcin Wojtas 
569ded9da68SMarcin Wojtas 	if ((mask & flags) & GPIO_PIN_INPUT)
570ded9da68SMarcin Wojtas 		mv_gpio_out_en(dev, pin, 0);
571ded9da68SMarcin Wojtas 	if ((mask & flags) & GPIO_PIN_OUTPUT) {
572ded9da68SMarcin Wojtas 		if ((flags & mask) & GPIO_PIN_OPENDRAIN)
573ded9da68SMarcin Wojtas 			mv_gpio_value_set(dev, pin, 0);
574ded9da68SMarcin Wojtas 		else
575ded9da68SMarcin Wojtas 			mv_gpio_value_set(dev, pin, 1);
576ded9da68SMarcin Wojtas 		mv_gpio_out_en(dev, pin, 1);
577ded9da68SMarcin Wojtas 	}
578ded9da68SMarcin Wojtas 
5791c45bd11SMarcin Wojtas 	if (mask & MV_GPIO_OUT_BLINK)
580edf9ef73SMarcin Wojtas 		mv_gpio_blink(dev, pin, flags & MV_GPIO_OUT_BLINK);
5811c45bd11SMarcin Wojtas 	if (mask & MV_GPIO_IN_POL_LOW)
582edf9ef73SMarcin Wojtas 		mv_gpio_polarity(dev, pin, flags & MV_GPIO_IN_POL_LOW, 0);
5831c45bd11SMarcin Wojtas 	if (mask & MV_GPIO_IN_DEBOUNCE) {
584edf9ef73SMarcin Wojtas 		error = mv_gpio_debounce_setup(dev, pin);
5851c45bd11SMarcin Wojtas 		if (error) {
5861c45bd11SMarcin Wojtas 			MV_GPIO_UNLOCK();
5871c45bd11SMarcin Wojtas 			return (error);
5881c45bd11SMarcin Wojtas 		}
5891c45bd11SMarcin Wojtas 	}
5901c45bd11SMarcin Wojtas 
591edf9ef73SMarcin Wojtas 	sc->gpio_setup[pin].gp_flags &= ~(mask);
592edf9ef73SMarcin Wojtas 	sc->gpio_setup[pin].gp_flags |= (flags & mask);
5931c45bd11SMarcin Wojtas 
5941c45bd11SMarcin Wojtas 	MV_GPIO_UNLOCK();
595373bbe25SRafal Jaworowski 
596373bbe25SRafal Jaworowski 	return (0);
597373bbe25SRafal Jaworowski }
598373bbe25SRafal Jaworowski 
5991c45bd11SMarcin Wojtas static void
mv_gpio_double_edge_init(device_t dev,int pin)600edf9ef73SMarcin Wojtas mv_gpio_double_edge_init(device_t dev, int pin)
6011c45bd11SMarcin Wojtas {
6021c45bd11SMarcin Wojtas 	uint8_t raw_read;
60369c595edSJohn Baldwin 	struct mv_gpio_softc *sc __unused;
604edf9ef73SMarcin Wojtas 	sc = (struct mv_gpio_softc *)device_get_softc(dev);
6051c45bd11SMarcin Wojtas 
6061c45bd11SMarcin Wojtas 	MV_GPIO_ASSERT_LOCKED();
6071c45bd11SMarcin Wojtas 
608edf9ef73SMarcin Wojtas 	raw_read = (mv_gpio_value_get(dev, pin, 1) ? 1 : 0);
6091c45bd11SMarcin Wojtas 
6101c45bd11SMarcin Wojtas 	if (raw_read)
611edf9ef73SMarcin Wojtas 		mv_gpio_polarity(dev, pin, 1, 0);
6121c45bd11SMarcin Wojtas 	else
613edf9ef73SMarcin Wojtas 		mv_gpio_polarity(dev, pin, 0, 0);
6141c45bd11SMarcin Wojtas }
6151c45bd11SMarcin Wojtas 
6161c45bd11SMarcin Wojtas static int
mv_gpio_debounce_setup(device_t dev,int pin)617edf9ef73SMarcin Wojtas mv_gpio_debounce_setup(device_t dev, int pin)
6181c45bd11SMarcin Wojtas {
6191c45bd11SMarcin Wojtas 	struct callout *c;
620edf9ef73SMarcin Wojtas 	struct mv_gpio_softc *sc;
621edf9ef73SMarcin Wojtas 
622edf9ef73SMarcin Wojtas 	sc = (struct mv_gpio_softc *)device_get_softc(dev);
6231c45bd11SMarcin Wojtas 
6241c45bd11SMarcin Wojtas 	MV_GPIO_ASSERT_LOCKED();
6251c45bd11SMarcin Wojtas 
626edf9ef73SMarcin Wojtas 	c = sc->debounce_callouts[pin];
6271c45bd11SMarcin Wojtas 	if (c == NULL)
6281c45bd11SMarcin Wojtas 		return (ENXIO);
6291c45bd11SMarcin Wojtas 
6301c45bd11SMarcin Wojtas 	if (callout_active(c))
6311c45bd11SMarcin Wojtas 		callout_deactivate(c);
6321c45bd11SMarcin Wojtas 
6331c45bd11SMarcin Wojtas 	callout_stop(c);
6341c45bd11SMarcin Wojtas 
6351c45bd11SMarcin Wojtas 	return (0);
6361c45bd11SMarcin Wojtas }
6371c45bd11SMarcin Wojtas 
6381c45bd11SMarcin Wojtas static int
mv_gpio_debounce_prepare(device_t dev,int pin)639edf9ef73SMarcin Wojtas mv_gpio_debounce_prepare(device_t dev, int pin)
6401c45bd11SMarcin Wojtas {
6411c45bd11SMarcin Wojtas 	struct callout *c;
6421c45bd11SMarcin Wojtas 	struct mv_gpio_softc *sc;
6431c45bd11SMarcin Wojtas 
644edf9ef73SMarcin Wojtas 	sc = (struct mv_gpio_softc *)device_get_softc(dev);
6451c45bd11SMarcin Wojtas 
6461c45bd11SMarcin Wojtas 	c = sc->debounce_callouts[pin];
6471c45bd11SMarcin Wojtas 	if (c == NULL) {
6481c45bd11SMarcin Wojtas 		c = (struct callout *)malloc(sizeof(struct callout),
6491c45bd11SMarcin Wojtas 		    M_DEVBUF, M_WAITOK);
6501c45bd11SMarcin Wojtas 		sc->debounce_callouts[pin] = c;
6511c45bd11SMarcin Wojtas 		if (c == NULL)
6521c45bd11SMarcin Wojtas 			return (ENOMEM);
6531c45bd11SMarcin Wojtas 		callout_init(c, 1);
6541c45bd11SMarcin Wojtas 	}
6551c45bd11SMarcin Wojtas 
6561c45bd11SMarcin Wojtas 	return (0);
6571c45bd11SMarcin Wojtas }
6581c45bd11SMarcin Wojtas 
6591c45bd11SMarcin Wojtas static int
mv_gpio_debounce_init(device_t dev,int pin)660edf9ef73SMarcin Wojtas mv_gpio_debounce_init(device_t dev, int pin)
6611c45bd11SMarcin Wojtas {
6621c45bd11SMarcin Wojtas 	uint8_t raw_read;
6631c45bd11SMarcin Wojtas 	int *cnt;
664edf9ef73SMarcin Wojtas 	struct mv_gpio_softc *sc;
665edf9ef73SMarcin Wojtas 
666edf9ef73SMarcin Wojtas 	sc = (struct mv_gpio_softc *)device_get_softc(dev);
6671c45bd11SMarcin Wojtas 
6681c45bd11SMarcin Wojtas 	MV_GPIO_ASSERT_LOCKED();
6691c45bd11SMarcin Wojtas 
670edf9ef73SMarcin Wojtas 	cnt = &sc->debounce_counters[pin];
671edf9ef73SMarcin Wojtas 	raw_read = (mv_gpio_value_get(dev, pin, 1) ? 1 : 0);
6721c45bd11SMarcin Wojtas 	if (raw_read) {
673edf9ef73SMarcin Wojtas 		mv_gpio_polarity(dev, pin, 1, 0);
6741c45bd11SMarcin Wojtas 		*cnt = DEBOUNCE_HI_LO_MS / DEBOUNCE_CHECK_MS;
6751c45bd11SMarcin Wojtas 	} else {
676edf9ef73SMarcin Wojtas 		mv_gpio_polarity(dev, pin, 0, 0);
6771c45bd11SMarcin Wojtas 		*cnt = DEBOUNCE_LO_HI_MS / DEBOUNCE_CHECK_MS;
6781c45bd11SMarcin Wojtas 	}
6791c45bd11SMarcin Wojtas 
680edf9ef73SMarcin Wojtas 	mv_gpio_debounced_state_set(dev, pin, raw_read);
6811c45bd11SMarcin Wojtas 
6821c45bd11SMarcin Wojtas 	return (0);
6831c45bd11SMarcin Wojtas }
6841c45bd11SMarcin Wojtas 
6851c45bd11SMarcin Wojtas static void
mv_gpio_debounce_start(device_t dev,int pin)686edf9ef73SMarcin Wojtas mv_gpio_debounce_start(device_t dev, int pin)
6871c45bd11SMarcin Wojtas {
6881c45bd11SMarcin Wojtas 	struct callout *c;
689edf9ef73SMarcin Wojtas 	struct mv_gpio_pindev s = {dev, pin};
690edf9ef73SMarcin Wojtas 	struct mv_gpio_pindev *sd;
691edf9ef73SMarcin Wojtas 	struct mv_gpio_softc *sc;
692edf9ef73SMarcin Wojtas 	sc = (struct mv_gpio_softc *)device_get_softc(dev);
6931c45bd11SMarcin Wojtas 
6941c45bd11SMarcin Wojtas 	MV_GPIO_ASSERT_LOCKED();
6951c45bd11SMarcin Wojtas 
696edf9ef73SMarcin Wojtas 	c = sc->debounce_callouts[pin];
6971c45bd11SMarcin Wojtas 	if (c == NULL) {
698edf9ef73SMarcin Wojtas 		mv_gpio_int_ack(&s);
6991c45bd11SMarcin Wojtas 		return;
7001c45bd11SMarcin Wojtas 	}
7011c45bd11SMarcin Wojtas 
7021c45bd11SMarcin Wojtas 	if (callout_pending(c) || callout_active(c)) {
703edf9ef73SMarcin Wojtas 		mv_gpio_int_ack(&s);
7041c45bd11SMarcin Wojtas 		return;
7051c45bd11SMarcin Wojtas 	}
7061c45bd11SMarcin Wojtas 
707edf9ef73SMarcin Wojtas 	sd = (struct mv_gpio_pindev *)malloc(sizeof(struct mv_gpio_pindev),
708edf9ef73SMarcin Wojtas 	    M_DEVBUF, M_WAITOK);
709edf9ef73SMarcin Wojtas 	if (sd == NULL) {
710edf9ef73SMarcin Wojtas 		mv_gpio_int_ack(&s);
7111c45bd11SMarcin Wojtas 		return;
7121c45bd11SMarcin Wojtas 	}
713edf9ef73SMarcin Wojtas 	sd->pin = pin;
714edf9ef73SMarcin Wojtas 	sd->dev = dev;
7151c45bd11SMarcin Wojtas 
716edf9ef73SMarcin Wojtas 	callout_reset(c, DEBOUNCE_CHECK_TICKS, mv_gpio_debounce, sd);
7171c45bd11SMarcin Wojtas }
7181c45bd11SMarcin Wojtas 
7191c45bd11SMarcin Wojtas static void
mv_gpio_debounce(void * arg)7201c45bd11SMarcin Wojtas mv_gpio_debounce(void *arg)
7211c45bd11SMarcin Wojtas {
7221c45bd11SMarcin Wojtas 	uint8_t raw_read, last_state;
7231c45bd11SMarcin Wojtas 	int pin;
724edf9ef73SMarcin Wojtas 	device_t dev;
7251c45bd11SMarcin Wojtas 	int *debounce_counter;
726edf9ef73SMarcin Wojtas 	struct mv_gpio_softc *sc;
727edf9ef73SMarcin Wojtas 	struct mv_gpio_pindev *s;
7281c45bd11SMarcin Wojtas 
729edf9ef73SMarcin Wojtas 	s = (struct mv_gpio_pindev *)arg;
730edf9ef73SMarcin Wojtas 	dev = s->dev;
731edf9ef73SMarcin Wojtas 	pin = s->pin;
732edf9ef73SMarcin Wojtas 	sc = (struct mv_gpio_softc *)device_get_softc(dev);
7331c45bd11SMarcin Wojtas 
7341c45bd11SMarcin Wojtas 	MV_GPIO_LOCK();
7351c45bd11SMarcin Wojtas 
736edf9ef73SMarcin Wojtas 	raw_read = (mv_gpio_value_get(dev, pin, 1) ? 1 : 0);
737edf9ef73SMarcin Wojtas 	last_state = (mv_gpio_debounced_state_get(dev, pin) ? 1 : 0);
738edf9ef73SMarcin Wojtas 	debounce_counter = &sc->debounce_counters[pin];
7391c45bd11SMarcin Wojtas 
7401c45bd11SMarcin Wojtas 	if (raw_read == last_state) {
7411c45bd11SMarcin Wojtas 		if (last_state)
7421c45bd11SMarcin Wojtas 			*debounce_counter = DEBOUNCE_HI_LO_MS /
7431c45bd11SMarcin Wojtas 			    DEBOUNCE_CHECK_MS;
7441c45bd11SMarcin Wojtas 		else
7451c45bd11SMarcin Wojtas 			*debounce_counter = DEBOUNCE_LO_HI_MS /
7461c45bd11SMarcin Wojtas 			    DEBOUNCE_CHECK_MS;
7471c45bd11SMarcin Wojtas 
748edf9ef73SMarcin Wojtas 		callout_reset(sc->debounce_callouts[pin],
7491c45bd11SMarcin Wojtas 		    DEBOUNCE_CHECK_TICKS, mv_gpio_debounce, arg);
7501c45bd11SMarcin Wojtas 	} else {
7511c45bd11SMarcin Wojtas 		*debounce_counter = *debounce_counter - 1;
7521c45bd11SMarcin Wojtas 		if (*debounce_counter != 0)
753edf9ef73SMarcin Wojtas 			callout_reset(sc->debounce_callouts[pin],
7541c45bd11SMarcin Wojtas 			    DEBOUNCE_CHECK_TICKS, mv_gpio_debounce, arg);
7551c45bd11SMarcin Wojtas 		else {
756edf9ef73SMarcin Wojtas 			mv_gpio_debounced_state_set(dev, pin, raw_read);
7571c45bd11SMarcin Wojtas 
7581c45bd11SMarcin Wojtas 			if (last_state)
7591c45bd11SMarcin Wojtas 				*debounce_counter = DEBOUNCE_HI_LO_MS /
7601c45bd11SMarcin Wojtas 				    DEBOUNCE_CHECK_MS;
7611c45bd11SMarcin Wojtas 			else
7621c45bd11SMarcin Wojtas 				*debounce_counter = DEBOUNCE_LO_HI_MS /
7631c45bd11SMarcin Wojtas 				    DEBOUNCE_CHECK_MS;
7641c45bd11SMarcin Wojtas 
765edf9ef73SMarcin Wojtas 			if (((sc->gpio_setup[pin].gp_flags & MV_GPIO_IN_POL_LOW) &&
7661c45bd11SMarcin Wojtas 			    (raw_read == 0)) ||
767edf9ef73SMarcin Wojtas 			    (((sc->gpio_setup[pin].gp_flags & MV_GPIO_IN_POL_LOW) == 0) &&
7681c45bd11SMarcin Wojtas 			    raw_read) ||
769edf9ef73SMarcin Wojtas 			    (sc->gpio_setup[pin].gp_flags & MV_GPIO_IN_IRQ_DOUBLE_EDGE))
770edf9ef73SMarcin Wojtas 				mv_gpio_intr_handler(dev, pin);
7711c45bd11SMarcin Wojtas 
7721c45bd11SMarcin Wojtas 			/* Toggle polarity for next edge. */
773edf9ef73SMarcin Wojtas 			mv_gpio_polarity(dev, pin, 0, 1);
7741c45bd11SMarcin Wojtas 
7751c45bd11SMarcin Wojtas 			free(arg, M_DEVBUF);
776edf9ef73SMarcin Wojtas 			callout_deactivate(sc->debounce_callouts[pin]);
7771c45bd11SMarcin Wojtas 		}
7781c45bd11SMarcin Wojtas 	}
7791c45bd11SMarcin Wojtas 
7801c45bd11SMarcin Wojtas 	MV_GPIO_UNLOCK();
7811c45bd11SMarcin Wojtas }
7821c45bd11SMarcin Wojtas 
7831c45bd11SMarcin Wojtas static void
mv_gpio_debounced_state_set(device_t dev,int pin,uint8_t new_state)784edf9ef73SMarcin Wojtas mv_gpio_debounced_state_set(device_t dev, int pin, uint8_t new_state)
7851c45bd11SMarcin Wojtas {
7861c45bd11SMarcin Wojtas 	uint32_t *old_state;
787edf9ef73SMarcin Wojtas 	struct mv_gpio_softc *sc;
788edf9ef73SMarcin Wojtas 	sc = (struct mv_gpio_softc *)device_get_softc(dev);
7891c45bd11SMarcin Wojtas 
7901c45bd11SMarcin Wojtas 	MV_GPIO_ASSERT_LOCKED();
7911c45bd11SMarcin Wojtas 
7921c45bd11SMarcin Wojtas 	if (pin >= GPIO_PINS_PER_REG) {
793edf9ef73SMarcin Wojtas 		old_state = &sc->debounced_state_hi;
7941c45bd11SMarcin Wojtas 		pin -= GPIO_PINS_PER_REG;
7951c45bd11SMarcin Wojtas 	} else
796edf9ef73SMarcin Wojtas 		old_state = &sc->debounced_state_lo;
7971c45bd11SMarcin Wojtas 
7981c45bd11SMarcin Wojtas 	if (new_state)
7991c45bd11SMarcin Wojtas 		*old_state |= (1 << pin);
8001c45bd11SMarcin Wojtas 	else
8011c45bd11SMarcin Wojtas 		*old_state &= ~(1 << pin);
8021c45bd11SMarcin Wojtas }
8031c45bd11SMarcin Wojtas 
8041c45bd11SMarcin Wojtas static uint32_t
mv_gpio_debounced_state_get(device_t dev,int pin)805edf9ef73SMarcin Wojtas mv_gpio_debounced_state_get(device_t dev, int pin)
8061c45bd11SMarcin Wojtas {
8071c45bd11SMarcin Wojtas 	uint32_t *state;
808edf9ef73SMarcin Wojtas 	struct mv_gpio_softc *sc;
809edf9ef73SMarcin Wojtas 	sc = (struct mv_gpio_softc *)device_get_softc(dev);
8101c45bd11SMarcin Wojtas 
8111c45bd11SMarcin Wojtas 	MV_GPIO_ASSERT_LOCKED();
8121c45bd11SMarcin Wojtas 
8131c45bd11SMarcin Wojtas 	if (pin >= GPIO_PINS_PER_REG) {
814edf9ef73SMarcin Wojtas 		state = &sc->debounced_state_hi;
8151c45bd11SMarcin Wojtas 		pin -= GPIO_PINS_PER_REG;
8161c45bd11SMarcin Wojtas 	} else
817edf9ef73SMarcin Wojtas 		state = &sc->debounced_state_lo;
8181c45bd11SMarcin Wojtas 
8191c45bd11SMarcin Wojtas 	return (*state & (1 << pin));
8201c45bd11SMarcin Wojtas }
8211c45bd11SMarcin Wojtas 
822373bbe25SRafal Jaworowski void
mv_gpio_out(device_t dev,uint32_t pin,uint8_t val,uint8_t enable)823edf9ef73SMarcin Wojtas mv_gpio_out(device_t dev, uint32_t pin, uint8_t val, uint8_t enable)
824373bbe25SRafal Jaworowski {
825edf9ef73SMarcin Wojtas 	struct mv_gpio_softc *sc;
826edf9ef73SMarcin Wojtas 	sc = (struct mv_gpio_softc *)device_get_softc(dev);
827373bbe25SRafal Jaworowski 
8281c45bd11SMarcin Wojtas 	MV_GPIO_LOCK();
8291c45bd11SMarcin Wojtas 
830edf9ef73SMarcin Wojtas 	mv_gpio_value_set(dev, pin, val);
831edf9ef73SMarcin Wojtas 	mv_gpio_out_en(dev, pin, enable);
8321c45bd11SMarcin Wojtas 
8331c45bd11SMarcin Wojtas 	MV_GPIO_UNLOCK();
834373bbe25SRafal Jaworowski }
835373bbe25SRafal Jaworowski 
836373bbe25SRafal Jaworowski uint8_t
mv_gpio_in(device_t dev,uint32_t pin)837edf9ef73SMarcin Wojtas mv_gpio_in(device_t dev, uint32_t pin)
838373bbe25SRafal Jaworowski {
8391c45bd11SMarcin Wojtas 	uint8_t state;
840edf9ef73SMarcin Wojtas 	struct mv_gpio_softc *sc;
841edf9ef73SMarcin Wojtas 	sc = (struct mv_gpio_softc *)device_get_softc(dev);
842373bbe25SRafal Jaworowski 
843ded9da68SMarcin Wojtas 	MV_GPIO_ASSERT_LOCKED();
8441c45bd11SMarcin Wojtas 
845edf9ef73SMarcin Wojtas 	if (sc->gpio_setup[pin].gp_flags & MV_GPIO_IN_DEBOUNCE) {
846edf9ef73SMarcin Wojtas 		if (sc->gpio_setup[pin].gp_flags & MV_GPIO_IN_POL_LOW)
847edf9ef73SMarcin Wojtas 			state = (mv_gpio_debounced_state_get(dev, pin) ? 0 : 1);
8481c45bd11SMarcin Wojtas 		else
849edf9ef73SMarcin Wojtas 			state = (mv_gpio_debounced_state_get(dev, pin) ? 1 : 0);
850edf9ef73SMarcin Wojtas 	} else if (sc->gpio_setup[pin].gp_flags & MV_GPIO_IN_IRQ_DOUBLE_EDGE) {
851edf9ef73SMarcin Wojtas 		if (sc->gpio_setup[pin].gp_flags & MV_GPIO_IN_POL_LOW)
852edf9ef73SMarcin Wojtas 			state = (mv_gpio_value_get(dev, pin, 1) ? 0 : 1);
8531c45bd11SMarcin Wojtas 		else
854edf9ef73SMarcin Wojtas 			state = (mv_gpio_value_get(dev, pin, 1) ? 1 : 0);
8551c45bd11SMarcin Wojtas 	} else
856edf9ef73SMarcin Wojtas 		state = (mv_gpio_value_get(dev, pin, 0) ? 1 : 0);
8571c45bd11SMarcin Wojtas 
8581c45bd11SMarcin Wojtas 	return (state);
859373bbe25SRafal Jaworowski }
860373bbe25SRafal Jaworowski 
861373bbe25SRafal Jaworowski static uint32_t
mv_gpio_reg_read(device_t dev,uint32_t reg)862edf9ef73SMarcin Wojtas mv_gpio_reg_read(device_t dev, uint32_t reg)
863373bbe25SRafal Jaworowski {
864edf9ef73SMarcin Wojtas 	struct mv_gpio_softc *sc;
865edf9ef73SMarcin Wojtas 	sc = (struct mv_gpio_softc *)device_get_softc(dev);
866373bbe25SRafal Jaworowski 
8674f3a5b51SEmmanuel Vadot 	return (bus_space_read_4(sc->bst, sc->bsh, sc->offset + reg));
868373bbe25SRafal Jaworowski }
869373bbe25SRafal Jaworowski 
870373bbe25SRafal Jaworowski static void
mv_gpio_reg_write(device_t dev,uint32_t reg,uint32_t val)871edf9ef73SMarcin Wojtas mv_gpio_reg_write(device_t dev, uint32_t reg, uint32_t val)
872373bbe25SRafal Jaworowski {
873edf9ef73SMarcin Wojtas 	struct mv_gpio_softc *sc;
874edf9ef73SMarcin Wojtas 	sc = (struct mv_gpio_softc *)device_get_softc(dev);
875373bbe25SRafal Jaworowski 
8764f3a5b51SEmmanuel Vadot 	bus_space_write_4(sc->bst, sc->bsh, sc->offset + reg, val);
877373bbe25SRafal Jaworowski }
878373bbe25SRafal Jaworowski 
879373bbe25SRafal Jaworowski static void
mv_gpio_reg_set(device_t dev,uint32_t reg,uint32_t pin)880edf9ef73SMarcin Wojtas mv_gpio_reg_set(device_t dev, uint32_t reg, uint32_t pin)
881373bbe25SRafal Jaworowski {
882373bbe25SRafal Jaworowski 	uint32_t reg_val;
883373bbe25SRafal Jaworowski 
884edf9ef73SMarcin Wojtas 	reg_val = mv_gpio_reg_read(dev, reg);
885373bbe25SRafal Jaworowski 	reg_val |= GPIO(pin);
886edf9ef73SMarcin Wojtas 	mv_gpio_reg_write(dev, reg, reg_val);
887373bbe25SRafal Jaworowski }
888373bbe25SRafal Jaworowski 
889373bbe25SRafal Jaworowski static void
mv_gpio_reg_clear(device_t dev,uint32_t reg,uint32_t pin)890edf9ef73SMarcin Wojtas mv_gpio_reg_clear(device_t dev, uint32_t reg, uint32_t pin)
891373bbe25SRafal Jaworowski {
892373bbe25SRafal Jaworowski 	uint32_t reg_val;
893373bbe25SRafal Jaworowski 
894edf9ef73SMarcin Wojtas 	reg_val = mv_gpio_reg_read(dev, reg);
895373bbe25SRafal Jaworowski 	reg_val &= ~(GPIO(pin));
896edf9ef73SMarcin Wojtas 	mv_gpio_reg_write(dev, reg, reg_val);
897373bbe25SRafal Jaworowski }
898373bbe25SRafal Jaworowski 
899373bbe25SRafal Jaworowski static void
mv_gpio_out_en(device_t dev,uint32_t pin,uint8_t enable)900edf9ef73SMarcin Wojtas mv_gpio_out_en(device_t dev, uint32_t pin, uint8_t enable)
901373bbe25SRafal Jaworowski {
902373bbe25SRafal Jaworowski 	uint32_t reg;
903edf9ef73SMarcin Wojtas 	struct mv_gpio_softc *sc;
904edf9ef73SMarcin Wojtas 	sc = (struct mv_gpio_softc *)device_get_softc(dev);
905373bbe25SRafal Jaworowski 
906edf9ef73SMarcin Wojtas 	if (pin >= sc->pin_num)
907373bbe25SRafal Jaworowski 		return;
908373bbe25SRafal Jaworowski 
909373bbe25SRafal Jaworowski 	reg = GPIO_DATA_OUT_EN_CTRL;
910373bbe25SRafal Jaworowski 
911373bbe25SRafal Jaworowski 	if (enable)
912edf9ef73SMarcin Wojtas 		mv_gpio_reg_clear(dev, reg, pin);
913373bbe25SRafal Jaworowski 	else
914edf9ef73SMarcin Wojtas 		mv_gpio_reg_set(dev, reg, pin);
915373bbe25SRafal Jaworowski }
916373bbe25SRafal Jaworowski 
917373bbe25SRafal Jaworowski static void
mv_gpio_blink(device_t dev,uint32_t pin,uint8_t enable)918edf9ef73SMarcin Wojtas mv_gpio_blink(device_t dev, uint32_t pin, uint8_t enable)
919373bbe25SRafal Jaworowski {
920373bbe25SRafal Jaworowski 	uint32_t reg;
921edf9ef73SMarcin Wojtas 	struct mv_gpio_softc *sc;
922edf9ef73SMarcin Wojtas 	sc = (struct mv_gpio_softc *)device_get_softc(dev);
923373bbe25SRafal Jaworowski 
924edf9ef73SMarcin Wojtas 	if (pin >= sc->pin_num)
925373bbe25SRafal Jaworowski 		return;
926373bbe25SRafal Jaworowski 
927373bbe25SRafal Jaworowski 	reg = GPIO_BLINK_EN;
928373bbe25SRafal Jaworowski 
929373bbe25SRafal Jaworowski 	if (enable)
930edf9ef73SMarcin Wojtas 		mv_gpio_reg_set(dev, reg, pin);
931373bbe25SRafal Jaworowski 	else
932edf9ef73SMarcin Wojtas 		mv_gpio_reg_clear(dev, reg, pin);
933373bbe25SRafal Jaworowski }
934373bbe25SRafal Jaworowski 
935373bbe25SRafal Jaworowski static void
mv_gpio_polarity(device_t dev,uint32_t pin,uint8_t enable,uint8_t toggle)936edf9ef73SMarcin Wojtas mv_gpio_polarity(device_t dev, uint32_t pin, uint8_t enable, uint8_t toggle)
937373bbe25SRafal Jaworowski {
9381c45bd11SMarcin Wojtas 	uint32_t reg, reg_val;
939edf9ef73SMarcin Wojtas 	struct mv_gpio_softc *sc;
940edf9ef73SMarcin Wojtas 	sc = (struct mv_gpio_softc *)device_get_softc(dev);
941373bbe25SRafal Jaworowski 
942edf9ef73SMarcin Wojtas 	if (pin >= sc->pin_num)
943373bbe25SRafal Jaworowski 		return;
944373bbe25SRafal Jaworowski 
945373bbe25SRafal Jaworowski 	reg = GPIO_DATA_IN_POLAR;
946373bbe25SRafal Jaworowski 
9471c45bd11SMarcin Wojtas 	if (toggle) {
948edf9ef73SMarcin Wojtas 		reg_val = mv_gpio_reg_read(dev, reg) & GPIO(pin);
9491c45bd11SMarcin Wojtas 		if (reg_val)
950edf9ef73SMarcin Wojtas 			mv_gpio_reg_clear(dev, reg, pin);
9511c45bd11SMarcin Wojtas 		else
952edf9ef73SMarcin Wojtas 			mv_gpio_reg_set(dev, reg, pin);
9531c45bd11SMarcin Wojtas 	} else if (enable)
954edf9ef73SMarcin Wojtas 		mv_gpio_reg_set(dev, reg, pin);
955373bbe25SRafal Jaworowski 	else
956edf9ef73SMarcin Wojtas 		mv_gpio_reg_clear(dev, reg, pin);
957373bbe25SRafal Jaworowski }
958373bbe25SRafal Jaworowski 
959373bbe25SRafal Jaworowski static void
mv_gpio_level(device_t dev,uint32_t pin,uint8_t enable)960edf9ef73SMarcin Wojtas mv_gpio_level(device_t dev, uint32_t pin, uint8_t enable)
961373bbe25SRafal Jaworowski {
962373bbe25SRafal Jaworowski 	uint32_t reg;
963edf9ef73SMarcin Wojtas 	struct mv_gpio_softc *sc;
964edf9ef73SMarcin Wojtas 	sc = (struct mv_gpio_softc *)device_get_softc(dev);
965373bbe25SRafal Jaworowski 
966edf9ef73SMarcin Wojtas 	if (pin >= sc->pin_num)
967373bbe25SRafal Jaworowski 		return;
968373bbe25SRafal Jaworowski 
969373bbe25SRafal Jaworowski 	reg = GPIO_INT_LEV_MASK;
970373bbe25SRafal Jaworowski 
971373bbe25SRafal Jaworowski 	if (enable)
972edf9ef73SMarcin Wojtas 		mv_gpio_reg_set(dev, reg, pin);
973373bbe25SRafal Jaworowski 	else
974edf9ef73SMarcin Wojtas 		mv_gpio_reg_clear(dev, reg, pin);
975373bbe25SRafal Jaworowski }
976373bbe25SRafal Jaworowski 
977373bbe25SRafal Jaworowski static void
mv_gpio_edge(device_t dev,uint32_t pin,uint8_t enable)978edf9ef73SMarcin Wojtas mv_gpio_edge(device_t dev, uint32_t pin, uint8_t enable)
979373bbe25SRafal Jaworowski {
980373bbe25SRafal Jaworowski 	uint32_t reg;
981edf9ef73SMarcin Wojtas 	struct mv_gpio_softc *sc;
982edf9ef73SMarcin Wojtas 	sc = (struct mv_gpio_softc *)device_get_softc(dev);
983373bbe25SRafal Jaworowski 
984edf9ef73SMarcin Wojtas 	if (pin >= sc->pin_num)
985373bbe25SRafal Jaworowski 		return;
986373bbe25SRafal Jaworowski 
987373bbe25SRafal Jaworowski 	reg = GPIO_INT_EDGE_MASK;
988373bbe25SRafal Jaworowski 
989373bbe25SRafal Jaworowski 	if (enable)
990edf9ef73SMarcin Wojtas 		mv_gpio_reg_set(dev, reg, pin);
991373bbe25SRafal Jaworowski 	else
992edf9ef73SMarcin Wojtas 		mv_gpio_reg_clear(dev, reg, pin);
993373bbe25SRafal Jaworowski }
994373bbe25SRafal Jaworowski 
995373bbe25SRafal Jaworowski static void
mv_gpio_int_ack(struct mv_gpio_pindev * s)996edf9ef73SMarcin Wojtas mv_gpio_int_ack(struct mv_gpio_pindev *s)
997373bbe25SRafal Jaworowski {
998edf9ef73SMarcin Wojtas 	uint32_t reg, pin;
999edf9ef73SMarcin Wojtas 	struct mv_gpio_softc *sc;
1000edf9ef73SMarcin Wojtas 	sc = (struct mv_gpio_softc *)device_get_softc(s->dev);
1001edf9ef73SMarcin Wojtas 	pin = s->pin;
1002373bbe25SRafal Jaworowski 
1003edf9ef73SMarcin Wojtas 	if (pin >= sc->pin_num)
1004373bbe25SRafal Jaworowski 		return;
1005373bbe25SRafal Jaworowski 
1006373bbe25SRafal Jaworowski 	reg = GPIO_INT_CAUSE;
1007373bbe25SRafal Jaworowski 
1008edf9ef73SMarcin Wojtas 	mv_gpio_reg_clear(s->dev, reg, pin);
1009373bbe25SRafal Jaworowski }
1010373bbe25SRafal Jaworowski 
1011373bbe25SRafal Jaworowski static uint32_t
mv_gpio_value_get(device_t dev,uint32_t pin,uint8_t exclude_polar)1012edf9ef73SMarcin Wojtas mv_gpio_value_get(device_t dev, uint32_t pin, uint8_t exclude_polar)
1013373bbe25SRafal Jaworowski {
10141c45bd11SMarcin Wojtas 	uint32_t reg, polar_reg, reg_val, polar_reg_val;
1015edf9ef73SMarcin Wojtas 	struct mv_gpio_softc *sc;
1016edf9ef73SMarcin Wojtas 	sc = (struct mv_gpio_softc *)device_get_softc(dev);
1017373bbe25SRafal Jaworowski 
1018edf9ef73SMarcin Wojtas 	if (pin >= sc->pin_num)
1019373bbe25SRafal Jaworowski 		return (0);
1020373bbe25SRafal Jaworowski 
1021373bbe25SRafal Jaworowski 	reg = GPIO_DATA_IN;
10221c45bd11SMarcin Wojtas 	polar_reg = GPIO_DATA_IN_POLAR;
1023373bbe25SRafal Jaworowski 
1024edf9ef73SMarcin Wojtas 	reg_val = mv_gpio_reg_read(dev, reg);
1025373bbe25SRafal Jaworowski 
10261c45bd11SMarcin Wojtas 	if (exclude_polar) {
1027edf9ef73SMarcin Wojtas 		polar_reg_val = mv_gpio_reg_read(dev, polar_reg);
10281c45bd11SMarcin Wojtas 		return ((reg_val & GPIO(pin)) ^ (polar_reg_val & GPIO(pin)));
10291c45bd11SMarcin Wojtas 	} else
1030373bbe25SRafal Jaworowski 		return (reg_val & GPIO(pin));
1031373bbe25SRafal Jaworowski }
1032373bbe25SRafal Jaworowski 
1033373bbe25SRafal Jaworowski static void
mv_gpio_value_set(device_t dev,uint32_t pin,uint8_t val)1034edf9ef73SMarcin Wojtas mv_gpio_value_set(device_t dev, uint32_t pin, uint8_t val)
1035373bbe25SRafal Jaworowski {
1036373bbe25SRafal Jaworowski 	uint32_t reg;
1037edf9ef73SMarcin Wojtas 	struct mv_gpio_softc *sc;
1038edf9ef73SMarcin Wojtas 	sc = (struct mv_gpio_softc *)device_get_softc(dev);
1039373bbe25SRafal Jaworowski 
1040ded9da68SMarcin Wojtas 	MV_GPIO_ASSERT_LOCKED();
1041ded9da68SMarcin Wojtas 
1042edf9ef73SMarcin Wojtas 	if (pin >= sc->pin_num)
1043373bbe25SRafal Jaworowski 		return;
1044373bbe25SRafal Jaworowski 
1045373bbe25SRafal Jaworowski 	reg = GPIO_DATA_OUT;
1046373bbe25SRafal Jaworowski 
1047373bbe25SRafal Jaworowski 	if (val)
1048edf9ef73SMarcin Wojtas 		mv_gpio_reg_set(dev, reg, pin);
1049373bbe25SRafal Jaworowski 	else
1050edf9ef73SMarcin Wojtas 		mv_gpio_reg_clear(dev, reg, pin);
1051373bbe25SRafal Jaworowski }
1052db5ef4fcSRafal Jaworowski 
1053db5ef4fcSRafal Jaworowski /*
10542a94dbf5SMarcin Wojtas  * GPIO interface methods
1055db5ef4fcSRafal Jaworowski  */
1056ded9da68SMarcin Wojtas 
1057ded9da68SMarcin Wojtas static int
mv_gpio_pin_max(device_t dev,int * maxpin)1058ded9da68SMarcin Wojtas mv_gpio_pin_max(device_t dev, int *maxpin)
1059ded9da68SMarcin Wojtas {
1060ded9da68SMarcin Wojtas 	struct mv_gpio_softc *sc;
1061ded9da68SMarcin Wojtas 	if (maxpin == NULL)
1062ded9da68SMarcin Wojtas 		return (EINVAL);
1063ded9da68SMarcin Wojtas 
1064ded9da68SMarcin Wojtas 	sc = device_get_softc(dev);
1065ded9da68SMarcin Wojtas 	*maxpin = sc->pin_num;
1066ded9da68SMarcin Wojtas 
1067db5ef4fcSRafal Jaworowski 	return (0);
1068db5ef4fcSRafal Jaworowski }
1069ded9da68SMarcin Wojtas 
1070ded9da68SMarcin Wojtas static int
mv_gpio_pin_getcaps(device_t dev,uint32_t pin,uint32_t * caps)1071ded9da68SMarcin Wojtas mv_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
1072ded9da68SMarcin Wojtas {
1073ded9da68SMarcin Wojtas 	struct mv_gpio_softc *sc = device_get_softc(dev);
1074ded9da68SMarcin Wojtas 	if (caps == NULL)
1075ded9da68SMarcin Wojtas 		return (EINVAL);
1076ded9da68SMarcin Wojtas 
1077ded9da68SMarcin Wojtas 	if (pin >= sc->pin_num)
1078ded9da68SMarcin Wojtas 		return (EINVAL);
1079ded9da68SMarcin Wojtas 
1080ded9da68SMarcin Wojtas 	MV_GPIO_LOCK();
1081ded9da68SMarcin Wojtas 	*caps = sc->gpio_setup[pin].gp_caps;
1082ded9da68SMarcin Wojtas 	MV_GPIO_UNLOCK();
1083ded9da68SMarcin Wojtas 
1084ded9da68SMarcin Wojtas 	return (0);
1085ded9da68SMarcin Wojtas }
1086ded9da68SMarcin Wojtas 
1087ded9da68SMarcin Wojtas static int
mv_gpio_pin_getflags(device_t dev,uint32_t pin,uint32_t * flags)1088ded9da68SMarcin Wojtas mv_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
1089ded9da68SMarcin Wojtas {
1090ded9da68SMarcin Wojtas 	struct mv_gpio_softc *sc = device_get_softc(dev);
1091ded9da68SMarcin Wojtas 	if (flags == NULL)
1092ded9da68SMarcin Wojtas 		return (EINVAL);
1093ded9da68SMarcin Wojtas 
1094ded9da68SMarcin Wojtas 	if (pin >= sc->pin_num)
1095ded9da68SMarcin Wojtas 		return (EINVAL);
1096ded9da68SMarcin Wojtas 
1097ded9da68SMarcin Wojtas 	MV_GPIO_LOCK();
1098ded9da68SMarcin Wojtas 	*flags = sc->gpio_setup[pin].gp_flags;
1099ded9da68SMarcin Wojtas 	MV_GPIO_UNLOCK();
1100ded9da68SMarcin Wojtas 
1101ded9da68SMarcin Wojtas 	return (0);
1102ded9da68SMarcin Wojtas }
1103ded9da68SMarcin Wojtas 
1104ded9da68SMarcin Wojtas static int
mv_gpio_pin_getname(device_t dev,uint32_t pin,char * name)1105ded9da68SMarcin Wojtas mv_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
1106ded9da68SMarcin Wojtas {
1107ded9da68SMarcin Wojtas 	struct mv_gpio_softc *sc = device_get_softc(dev);
1108ded9da68SMarcin Wojtas 	if (name == NULL)
1109ded9da68SMarcin Wojtas 		return (EINVAL);
1110ded9da68SMarcin Wojtas 
1111ded9da68SMarcin Wojtas 	if (pin >= sc->pin_num)
1112ded9da68SMarcin Wojtas 		return (EINVAL);
1113ded9da68SMarcin Wojtas 
1114ded9da68SMarcin Wojtas 	MV_GPIO_LOCK();
1115ded9da68SMarcin Wojtas 	memcpy(name, sc->gpio_setup[pin].gp_name, GPIOMAXNAME);
1116ded9da68SMarcin Wojtas 	MV_GPIO_UNLOCK();
1117ded9da68SMarcin Wojtas 
1118ded9da68SMarcin Wojtas 	return (0);
1119ded9da68SMarcin Wojtas }
1120ded9da68SMarcin Wojtas 
1121ded9da68SMarcin Wojtas static int
mv_gpio_pin_setflags(device_t dev,uint32_t pin,uint32_t flags)1122ded9da68SMarcin Wojtas mv_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
1123ded9da68SMarcin Wojtas {
1124ded9da68SMarcin Wojtas 	int ret;
1125ded9da68SMarcin Wojtas 	struct mv_gpio_softc *sc = device_get_softc(dev);
1126ded9da68SMarcin Wojtas 	if (pin >= sc->pin_num)
1127ded9da68SMarcin Wojtas 		return (EINVAL);
1128ded9da68SMarcin Wojtas 
1129ded9da68SMarcin Wojtas 	/* Check for unwanted flags. */
1130ded9da68SMarcin Wojtas 	if ((flags & sc->gpio_setup[pin].gp_caps) != flags)
1131ded9da68SMarcin Wojtas 		return (EINVAL);
1132ded9da68SMarcin Wojtas 
1133ded9da68SMarcin Wojtas 	ret = mv_gpio_configure(dev, pin, flags, ~0);
1134ded9da68SMarcin Wojtas 
1135ded9da68SMarcin Wojtas 	return (ret);
1136ded9da68SMarcin Wojtas }
1137ded9da68SMarcin Wojtas 
1138ded9da68SMarcin Wojtas static int
mv_gpio_pin_set(device_t dev,uint32_t pin,unsigned int value)1139ded9da68SMarcin Wojtas mv_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
1140ded9da68SMarcin Wojtas {
1141ded9da68SMarcin Wojtas 	struct mv_gpio_softc *sc = device_get_softc(dev);
1142ded9da68SMarcin Wojtas 	if (pin >= sc->pin_num)
1143ded9da68SMarcin Wojtas 		return (EINVAL);
1144ded9da68SMarcin Wojtas 
1145ded9da68SMarcin Wojtas 	MV_GPIO_LOCK();
1146ded9da68SMarcin Wojtas 	mv_gpio_value_set(dev, pin, value);
1147ded9da68SMarcin Wojtas 	MV_GPIO_UNLOCK();
1148ded9da68SMarcin Wojtas 
1149ded9da68SMarcin Wojtas 	return (0);
1150ded9da68SMarcin Wojtas }
1151ded9da68SMarcin Wojtas 
1152ded9da68SMarcin Wojtas static int
mv_gpio_pin_get(device_t dev,uint32_t pin,unsigned int * value)1153ded9da68SMarcin Wojtas mv_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *value)
1154ded9da68SMarcin Wojtas {
1155ded9da68SMarcin Wojtas 	struct mv_gpio_softc *sc = device_get_softc(dev);
1156ded9da68SMarcin Wojtas 	if (value == NULL)
1157ded9da68SMarcin Wojtas 		return (EINVAL);
1158ded9da68SMarcin Wojtas 
1159ded9da68SMarcin Wojtas 	if (pin >= sc->pin_num)
1160ded9da68SMarcin Wojtas 		return (EINVAL);
1161ded9da68SMarcin Wojtas 
1162ded9da68SMarcin Wojtas 	MV_GPIO_LOCK();
1163ded9da68SMarcin Wojtas 	*value = mv_gpio_in(dev, pin);
1164ded9da68SMarcin Wojtas 	MV_GPIO_UNLOCK();
1165ded9da68SMarcin Wojtas 
1166ded9da68SMarcin Wojtas 	return (0);
1167ded9da68SMarcin Wojtas }
1168ded9da68SMarcin Wojtas 
1169ded9da68SMarcin Wojtas static int
mv_gpio_pin_toggle(device_t dev,uint32_t pin)1170ded9da68SMarcin Wojtas mv_gpio_pin_toggle(device_t dev, uint32_t pin)
1171ded9da68SMarcin Wojtas {
1172ded9da68SMarcin Wojtas 	struct mv_gpio_softc *sc = device_get_softc(dev);
1173ded9da68SMarcin Wojtas 	uint32_t value;
1174ded9da68SMarcin Wojtas 	if (pin >= sc->pin_num)
1175ded9da68SMarcin Wojtas 		return (EINVAL);
1176ded9da68SMarcin Wojtas 
1177ded9da68SMarcin Wojtas 	MV_GPIO_LOCK();
1178ded9da68SMarcin Wojtas 	value = mv_gpio_in(dev, pin);
1179ded9da68SMarcin Wojtas 	value = (~value) & 1;
1180ded9da68SMarcin Wojtas 	mv_gpio_value_set(dev, pin, value);
1181ded9da68SMarcin Wojtas 	MV_GPIO_UNLOCK();
1182ded9da68SMarcin Wojtas 
1183ded9da68SMarcin Wojtas 	return (0);
1184ded9da68SMarcin Wojtas }
1185ded9da68SMarcin Wojtas 
1186ded9da68SMarcin Wojtas static device_t
mv_gpio_get_bus(device_t dev)1187ded9da68SMarcin Wojtas mv_gpio_get_bus(device_t dev)
1188ded9da68SMarcin Wojtas {
1189ded9da68SMarcin Wojtas 	struct mv_gpio_softc *sc = device_get_softc(dev);
1190ded9da68SMarcin Wojtas 
1191ded9da68SMarcin Wojtas 	return (sc->sc_busdev);
1192ded9da68SMarcin Wojtas }
11932a94dbf5SMarcin Wojtas 
11942a94dbf5SMarcin Wojtas static int
mv_gpio_map_gpios(device_t bus,phandle_t dev,phandle_t gparent,int gcells,pcell_t * gpios,uint32_t * pin,uint32_t * flags)11952a94dbf5SMarcin Wojtas mv_gpio_map_gpios(device_t bus, phandle_t dev, phandle_t gparent, int gcells,
11962a94dbf5SMarcin Wojtas     pcell_t *gpios, uint32_t *pin, uint32_t *flags)
11972a94dbf5SMarcin Wojtas {
11982a94dbf5SMarcin Wojtas 	struct mv_gpio_softc *sc = device_get_softc(bus);
11992a94dbf5SMarcin Wojtas 
12002a94dbf5SMarcin Wojtas 	if (gpios[0] >= sc->pin_num)
12012a94dbf5SMarcin Wojtas 		return (EINVAL);
12022a94dbf5SMarcin Wojtas 
12032a94dbf5SMarcin Wojtas 	*pin = gpios[0];
12042a94dbf5SMarcin Wojtas 	*flags = gpios[1];
12052a94dbf5SMarcin Wojtas 	mv_gpio_configure(bus, *pin, *flags, ~0);
12062a94dbf5SMarcin Wojtas 
12072a94dbf5SMarcin Wojtas 	return (0);
12082a94dbf5SMarcin Wojtas }
1209