rt305x_gpio.c revision 278782
1273562Smarcel/*-
2273562Smarcel * Copyright (c) 2010-2011, Aleksandr Rybalko <ray@ddteam.net>
3273562Smarcel * Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org>
4273562Smarcel * Copyright (c) 2009, Luiz Otavio O Souza.
5273562Smarcel * All rights reserved.
6273562Smarcel *
7273562Smarcel * Redistribution and use in source and binary forms, with or without
8273562Smarcel * modification, are permitted provided that the following conditions
9273562Smarcel * are met:
10273562Smarcel * 1. Redistributions of source code must retain the above copyright
11273562Smarcel *    notice unmodified, this list of conditions, and the following
12273562Smarcel *    disclaimer.
13273562Smarcel * 2. Redistributions in binary form must reproduce the above copyright
14273562Smarcel *    notice, this list of conditions and the following disclaimer in the
15273562Smarcel *    documentation and/or other materials provided with the distribution.
16273562Smarcel *
17273562Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18273562Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19273562Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20273562Smarcel * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21273562Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22273562Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23273562Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24273562Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25273562Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26273562Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27273562Smarcel * SUCH DAMAGE.
28273562Smarcel */
29273562Smarcel
30273562Smarcel/*
31274672Smarcel * GPIO driver for RT305X SoC.
32274672Smarcel */
33274672Smarcel
34274672Smarcel#include <sys/cdefs.h>
35274672Smarcel__FBSDID("$FreeBSD: stable/10/sys/mips/rt305x/rt305x_gpio.c 278782 2015-02-14 20:37:33Z loos $");
36274672Smarcel
37274672Smarcel#include <sys/param.h>
38274672Smarcel#include <sys/systm.h>
39274672Smarcel#include <sys/bus.h>
40274672Smarcel
41274672Smarcel#include <sys/kernel.h>
42274672Smarcel#include <sys/module.h>
43274672Smarcel#include <sys/rman.h>
44273562Smarcel#include <sys/lock.h>
45273562Smarcel#include <sys/mutex.h>
46273562Smarcel#include <sys/gpio.h>
47273562Smarcel
48273562Smarcel#include <machine/bus.h>
49273562Smarcel#include <machine/resource.h>
50273562Smarcel#include <mips/rt305x/rt305xreg.h>
51273562Smarcel#include <mips/rt305x/rt305x_gpio.h>
52273562Smarcel#include <mips/rt305x/rt305x_gpiovar.h>
53273562Smarcel#include <mips/rt305x/rt305x_sysctlvar.h>
54273562Smarcel
55273562Smarcel#include "gpio_if.h"
56273562Smarcel
57273562Smarcel#ifdef	notyet
58273562Smarcel#define	DEFAULT_CAPS	(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_INVIN | \
59273562Smarcel 		         GPIO_PIN_INVOUT | GPIO_PIN_REPORT )
60273562Smarcel#else
61273562Smarcel#define	DEFAULT_CAPS	(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_INVIN | \
62273562Smarcel 		         GPIO_PIN_INVOUT )
63273562Smarcel#endif
64273562Smarcel
65273562Smarcel/*
66273562Smarcel * Helpers
67273562Smarcel */
68273562Smarcelstatic void rt305x_gpio_pin_configure(struct rt305x_gpio_softc *sc,
69273562Smarcel    struct gpio_pin *pin, uint32_t flags);
70273562Smarcel
71273562Smarcel/*
72273562Smarcel * Driver stuff
73273562Smarcel */
74273562Smarcelstatic int rt305x_gpio_probe(device_t dev);
75273562Smarcelstatic int rt305x_gpio_attach(device_t dev);
76273562Smarcelstatic int rt305x_gpio_detach(device_t dev);
77273562Smarcelstatic int rt305x_gpio_intr(void *arg);
78273562Smarcel
79273562Smarcelint 	rt305x_get_int_mask  (device_t);
80273562Smarcelvoid 	rt305x_set_int_mask  (device_t, uint32_t);
81273562Smarcelint 	rt305x_get_int_status(device_t);
82273562Smarcelvoid 	rt305x_set_int_status(device_t, uint32_t);
83273562Smarcel
84273562Smarcel/*
85273562Smarcel * GPIO interface
86273562Smarcel */
87273562Smarcelstatic int rt305x_gpio_pin_max(device_t dev, int *maxpin);
88273562Smarcelstatic int rt305x_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps);
89273562Smarcelstatic int rt305x_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t
90273562Smarcel    *flags);
91273562Smarcelstatic int rt305x_gpio_pin_getname(device_t dev, uint32_t pin, char *name);
92273562Smarcelstatic int rt305x_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags);
93273562Smarcelstatic int rt305x_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value);
94273562Smarcelstatic int rt305x_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val);
95273562Smarcelstatic int rt305x_gpio_pin_toggle(device_t dev, uint32_t pin);
96273562Smarcel
97273562Smarcelstatic void
98273562Smarcelrt305x_gpio_pin_configure(struct rt305x_gpio_softc *sc, struct gpio_pin *pin,
99273562Smarcel    unsigned int flags)
100273562Smarcel{
101273562Smarcel	GPIO_LOCK(sc);
102273562Smarcel
103273562Smarcel	/*
104273562Smarcel	 * Manage input/output
105273562Smarcel	 */
106273562Smarcel	if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) {
107273562Smarcel		pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT);
108273562Smarcel		if (flags & GPIO_PIN_OUTPUT) {
109273562Smarcel			pin->gp_flags |= GPIO_PIN_OUTPUT;
110273562Smarcel			GPIO_BIT_SET(sc, pin->gp_pin, DIR);
111273562Smarcel		}
112273562Smarcel		else {
113273562Smarcel			pin->gp_flags |= GPIO_PIN_INPUT;
114273562Smarcel			GPIO_BIT_CLR(sc, pin->gp_pin, DIR);
115273562Smarcel		}
116273562Smarcel	}
117273562Smarcel
118273562Smarcel	if (flags & GPIO_PIN_INVOUT) {
119273562Smarcel		pin->gp_flags |= GPIO_PIN_INVOUT;
120273562Smarcel		GPIO_BIT_SET(sc, pin->gp_pin, POL);
121273562Smarcel	}
122273562Smarcel	else {
123273562Smarcel		pin->gp_flags &= ~GPIO_PIN_INVOUT;
124273562Smarcel		GPIO_BIT_CLR(sc, pin->gp_pin, POL);
125273562Smarcel	}
126273562Smarcel
127273562Smarcel	if (flags & GPIO_PIN_INVIN) {
128273562Smarcel		pin->gp_flags |= GPIO_PIN_INVIN;
129273562Smarcel		GPIO_BIT_SET(sc, pin->gp_pin, POL);
130273562Smarcel	}
131273562Smarcel	else {
132273562Smarcel		pin->gp_flags &= ~GPIO_PIN_INVIN;
133273562Smarcel		GPIO_BIT_CLR(sc, pin->gp_pin, POL);
134273562Smarcel	}
135273562Smarcel
136273562Smarcel#ifdef	notyet
137273562Smarcel	/* Enable interrupt bits for rising/falling transitions */
138273562Smarcel	if (flags & GPIO_PIN_REPORT) {
139273562Smarcel		pin->gp_flags |= GPIO_PIN_REPORT;
140273562Smarcel		GPIO_BIT_SET(sc, pin->gp_pin, RENA);
141273562Smarcel		GPIO_BIT_SET(sc, pin->gp_pin, FENA);
142273562Smarcel		device_printf(sc->dev, "Will report interrupt on pin %d\n",
143273562Smarcel		    pin->gp_pin);
144273562Smarcel
145273562Smarcel	}
146273562Smarcel	else {
147273562Smarcel		pin->gp_flags &= ~GPIO_PIN_REPORT;
148273562Smarcel		GPIO_BIT_CLR(sc, pin->gp_pin, RENA);
149273562Smarcel		GPIO_BIT_CLR(sc, pin->gp_pin, FENA);
150273562Smarcel	}
151273562Smarcel#else
152273562Smarcel	/* Disable generating interrupts for now */
153273562Smarcel	GPIO_BIT_CLR(sc, pin->gp_pin, RENA);
154273562Smarcel	GPIO_BIT_CLR(sc, pin->gp_pin, FENA);
155273562Smarcel#endif
156273562Smarcel
157273562Smarcel	GPIO_UNLOCK(sc);
158273562Smarcel}
159273562Smarcel
160273562Smarcelstatic int
161273562Smarcelrt305x_gpio_pin_max(device_t dev, int *maxpin)
162273562Smarcel{
163273562Smarcel
164273562Smarcel	*maxpin = NGPIO - 1;
165273562Smarcel	return (0);
166273562Smarcel}
167273562Smarcel
168273562Smarcelstatic int
169273562Smarcelrt305x_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
170273562Smarcel{
171273562Smarcel	struct rt305x_gpio_softc *sc = device_get_softc(dev);
172273562Smarcel	int i;
173273562Smarcel
174273562Smarcel	for (i = 0; i < sc->gpio_npins; i++) {
175273562Smarcel		if (sc->gpio_pins[i].gp_pin == pin)
176273562Smarcel			break;
177273562Smarcel	}
178273562Smarcel
179273562Smarcel	if (i >= sc->gpio_npins)
180273562Smarcel		return (EINVAL);
181273562Smarcel
182273562Smarcel	GPIO_LOCK(sc);
183273562Smarcel	*caps = sc->gpio_pins[i].gp_caps;
184273562Smarcel	GPIO_UNLOCK(sc);
185273562Smarcel
186273562Smarcel	return (0);
187273562Smarcel}
188273562Smarcel
189273562Smarcelstatic int
190273562Smarcelrt305x_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
191273562Smarcel{
192273562Smarcel	struct rt305x_gpio_softc *sc = device_get_softc(dev);
193273562Smarcel	int i;
194273562Smarcel
195273562Smarcel	for (i = 0; i < sc->gpio_npins; i++) {
196273562Smarcel		if (sc->gpio_pins[i].gp_pin == pin)
197273562Smarcel			break;
198273562Smarcel	}
199273562Smarcel
200273562Smarcel	if (i >= sc->gpio_npins)
201273562Smarcel		return (EINVAL);
202273562Smarcel
203273562Smarcel	GPIO_LOCK(sc);
204273562Smarcel	*flags = sc->gpio_pins[i].gp_flags;
205273562Smarcel	GPIO_UNLOCK(sc);
206273562Smarcel
207273562Smarcel	return (0);
208273562Smarcel}
209273562Smarcel
210273562Smarcelstatic int
211273562Smarcelrt305x_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
212273562Smarcel{
213273562Smarcel	struct rt305x_gpio_softc *sc = device_get_softc(dev);
214273562Smarcel	int i;
215273562Smarcel
216273562Smarcel	for (i = 0; i < sc->gpio_npins; i++) {
217273562Smarcel		if (sc->gpio_pins[i].gp_pin == pin)
218273562Smarcel			break;
219273562Smarcel	}
220273562Smarcel
221273562Smarcel	if (i >= sc->gpio_npins)
222273562Smarcel		return (EINVAL);
223273562Smarcel
224273562Smarcel	GPIO_LOCK(sc);
225273562Smarcel	memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME);
226273562Smarcel	GPIO_UNLOCK(sc);
227273562Smarcel
228273562Smarcel	return (0);
229273562Smarcel}
230273562Smarcel
231273562Smarcelstatic int
232273562Smarcelrt305x_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
233273562Smarcel{
234273562Smarcel	int i;
235273562Smarcel	struct rt305x_gpio_softc *sc = device_get_softc(dev);
236273562Smarcel
237273562Smarcel	for (i = 0; i < sc->gpio_npins; i++) {
238273562Smarcel		if (sc->gpio_pins[i].gp_pin == pin)
239273562Smarcel			break;
240273562Smarcel	}
241273562Smarcel
242273562Smarcel	if (i >= sc->gpio_npins)
243273562Smarcel		return (EINVAL);
244273562Smarcel
245273562Smarcel	/* Check for unwanted flags. */
246273562Smarcel	if ((flags & sc->gpio_pins[i].gp_caps) != flags)
247273562Smarcel		return (EINVAL);
248273562Smarcel
249273562Smarcel	/* Can't mix input/output together */
250273562Smarcel	if ((flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) ==
251273562Smarcel	    (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT))
252273562Smarcel		return (EINVAL);
253273562Smarcel
254273562Smarcel	rt305x_gpio_pin_configure(sc, &sc->gpio_pins[i], flags);
255273562Smarcel
256273562Smarcel
257273562Smarcel	return (0);
258273562Smarcel}
259273562Smarcel
260273562Smarcelstatic int
261273562Smarcelrt305x_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
262273562Smarcel{
263273562Smarcel	struct rt305x_gpio_softc *sc = device_get_softc(dev);
264273562Smarcel	int i;
265273562Smarcel
266273562Smarcel	for (i = 0; i < sc->gpio_npins; i++) {
267273562Smarcel		if (sc->gpio_pins[i].gp_pin == pin)
268273562Smarcel			break;
269273562Smarcel	}
270273562Smarcel
271273562Smarcel	if (i >= sc->gpio_npins)
272273562Smarcel		return (EINVAL);
273273562Smarcel
274273562Smarcel
275273562Smarcel	GPIO_LOCK(sc);
276273562Smarcel	if (value) GPIO_BIT_SET(sc, i, DATA);
277273562Smarcel	else       GPIO_BIT_CLR(sc, i, DATA);
278273562Smarcel	GPIO_UNLOCK(sc);
279273562Smarcel
280273562Smarcel	return (0);
281273562Smarcel}
282273562Smarcel
283273562Smarcelstatic int
284273562Smarcelrt305x_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
285274672Smarcel{
286273562Smarcel	struct rt305x_gpio_softc *sc = device_get_softc(dev);
287273562Smarcel	int i;
288273562Smarcel
289273562Smarcel	for (i = 0; i < sc->gpio_npins; i++) {
290273562Smarcel		if (sc->gpio_pins[i].gp_pin == pin)
291273562Smarcel			break;
292273562Smarcel	}
293273562Smarcel
294273562Smarcel	if (i >= sc->gpio_npins)
295273562Smarcel		return (EINVAL);
296273562Smarcel
297273562Smarcel	GPIO_LOCK(sc);
298273562Smarcel	*val = GPIO_BIT_GET(sc, i, DATA);
299273562Smarcel	GPIO_UNLOCK(sc);
300273562Smarcel
301273562Smarcel	return (0);
302273562Smarcel}
303273562Smarcel
304273562Smarcelstatic int
305273562Smarcelrt305x_gpio_pin_toggle(device_t dev, uint32_t pin)
306273562Smarcel{
307273562Smarcel	int i;
308273562Smarcel	struct rt305x_gpio_softc *sc = device_get_softc(dev);
309273562Smarcel
310273562Smarcel	for (i = 0; i < sc->gpio_npins; i++) {
311273562Smarcel		if (sc->gpio_pins[i].gp_pin == pin)
312273562Smarcel			break;
313273562Smarcel	}
314273562Smarcel
315273562Smarcel	if (i >= sc->gpio_npins)
316273562Smarcel		return (EINVAL);
317273562Smarcel
318273562Smarcel	GPIO_LOCK(sc);
319273562Smarcel	GPIO_BIT_SET(sc, i, TOG);
320273562Smarcel	GPIO_UNLOCK(sc);
321273562Smarcel
322273562Smarcel	return (0);
323273562Smarcel}
324273562Smarcel
325273562Smarcelstatic int
326273562Smarcelrt305x_gpio_intr(void *arg)
327273562Smarcel{
328273562Smarcel	struct rt305x_gpio_softc *sc = arg;
329273562Smarcel#ifdef	notyet
330273562Smarcel	uint32_t i;
331273562Smarcel#endif
332273562Smarcel	uint64_t input, value;
333273562Smarcel#ifdef	notyet
334273562Smarcel	uint64_t reset_pin;
335273562Smarcel	char notify[16];
336273562Smarcel	char pinname[6];
337273562Smarcel#endif
338273562Smarcel
339273562Smarcel	/* Read all reported pins */
340273562Smarcel	input  = GPIO_READ_ALL(sc, INT);
341273562Smarcel	/* Clear int status */
342273562Smarcel	GPIO_WRITE_ALL(sc, INT, input);
343273562Smarcel	/* Clear report for OUTs */
344273562Smarcel	input &= ~GPIO_READ_ALL(sc, DIR);
345273562Smarcel	value = input & GPIO_READ_ALL(sc, DATA);
346273562Smarcel
347273562Smarcel	if (!input) goto intr_done;
348273562Smarcel
349273562Smarcel#ifdef	notyet
350282100Smarcel	/* if reset_gpio and this pin is input */
351282100Smarcel	if (sc->reset_gpio >= 0  && (input & (1 << sc->reset_gpio))) {
352273562Smarcel		/* get reset_gpio pin value */
353282100Smarcel		reset_pin = (value & (1 << sc->reset_gpio))?1:0;
354273562Smarcel		if ( sc->reset_gpio_last != reset_pin )	{
355273562Smarcel			/*
356273562Smarcel			 * if now reset is high, check how long
357273562Smarcel			 * and do reset if less than 2 seconds
358273562Smarcel			 */
359282100Smarcel			if ( reset_pin &&
360273562Smarcel			    (time_uptime - sc->reset_gpio_ontime) < 2 )
361273562Smarcel				shutdown_nice(0);
362273562Smarcel
363273562Smarcel			sc->reset_gpio_last = reset_pin;
364282100Smarcel			sc->reset_gpio_ontime = time_uptime;
365273562Smarcel		}
366273562Smarcel	}
367273562Smarcel
368273562Smarcel	for ( i = 0; i < NGPIO; i ++ )
369273562Smarcel	{
370273562Smarcel		/* Next if output pin */
371282100Smarcel		if ( !(( input >> i) & 1) ) continue;
372282100Smarcel
373282100Smarcel		if ( (((value & input) >> i) & 1) != sc->gpio_pins[i].gp_last )
374274672Smarcel		{
375282100Smarcel			/* !system=GPIO subsystem=pin7 type=PIN_HIGH period=3 */
376274672Smarcel			snprintf(notify , sizeof(notify ), "period=%d",
377274672Smarcel			    (uint32_t)time_uptime - sc->gpio_pins[i].gp_time);
378274672Smarcel			snprintf(pinname, sizeof(pinname), "pin%02d", i);
379274672Smarcel			devctl_notify("GPIO", pinname,
380274672Smarcel			    (((value & input) >> i) & 1)?"PIN_HIGH":"PIN_LOW",
381274672Smarcel			    notify);
382274672Smarcel			printf("GPIO[%s] %s %s\n", pinname,
383274672Smarcel			    (((value & input) >> i) & 1)?"PIN_HIGH":"PIN_LOW",
384274672Smarcel			    notify);
385274672Smarcel			sc->gpio_pins[i].gp_last = ((value & input) >> i) & 1;
386282100Smarcel			sc->gpio_pins[i].gp_time = time_uptime;
387282100Smarcel		}
388282100Smarcel
389282100Smarcel	}
390282100Smarcel#endif
391282100Smarcel
392282100Smarcelintr_done:
393282100Smarcel	return (FILTER_HANDLED);
394282100Smarcel}
395282100Smarcel
396282100Smarcelstatic int
397282100Smarcelrt305x_gpio_probe(device_t dev)
398282100Smarcel{
399282100Smarcel	device_set_desc(dev, "RT305X GPIO driver");
400282100Smarcel	return (0);
401282100Smarcel}
402282100Smarcel
403282100Smarcelstatic uint64_t
404282100Smarcelrt305x_gpio_init(device_t dev)
405282100Smarcel{
406282100Smarcel	uint64_t avl = ~0ULL;
407282100Smarcel	uint32_t gmode = rt305x_sysctl_get(SYSCTL_GPIOMODE);
408282100Smarcel	if (!(gmode & SYSCTL_GPIOMODE_RGMII_GPIO_MODE))
409282100Smarcel		avl &= ~RGMII_GPIO_MODE_MASK;
410282100Smarcel	if (!(gmode & SYSCTL_GPIOMODE_SDRAM_GPIO_MODE))
411282100Smarcel		avl &= ~SDRAM_GPIO_MODE_MASK;
412282100Smarcel	if (!(gmode & SYSCTL_GPIOMODE_MDIO_GPIO_MODE))
413282100Smarcel		avl &= ~MDIO_GPIO_MODE_MASK;
414282100Smarcel	if (!(gmode & SYSCTL_GPIOMODE_JTAG_GPIO_MODE))
415282100Smarcel		avl &= ~JTAG_GPIO_MODE_MASK;
416282100Smarcel	if (!(gmode & SYSCTL_GPIOMODE_UARTL_GPIO_MODE))
417282100Smarcel		avl &= ~UARTL_GPIO_MODE_MASK;
418282100Smarcel	if (!(gmode & SYSCTL_GPIOMODE_SPI_GPIO_MODE))
419282100Smarcel		avl &= ~SPI_GPIO_MODE_MASK;
420282100Smarcel	if (!(gmode & SYSCTL_GPIOMODE_I2C_GPIO_MODE))
421282100Smarcel		avl &= ~I2C_GPIO_MODE_MASK;
422282100Smarcel	if ((gmode & SYSCTL_GPIOMODE_UARTF_SHARE_MODE_GPIO) !=
423282100Smarcel	    SYSCTL_GPIOMODE_UARTF_SHARE_MODE_GPIO)
424282100Smarcel		avl &= ~I2C_GPIO_MODE_MASK;
425282100Smarcel/* D-Link DAP-1350 Board have
426282100Smarcel * MDIO_GPIO_MODE
427282100Smarcel * UARTF_GPIO_MODE
428282100Smarcel * SPI_GPIO_MODE
429273562Smarcel * I2C_GPIO_MODE
430273562Smarcel * So we have
431273562Smarcel * 00000001 10000000 01111111 11111110
432273562Smarcel*/
433273562Smarcel	return (avl);
434273562Smarcel
435273562Smarcel}
436273562Smarcel
437273562Smarcel#define DAP1350_RESET_GPIO	10
438273562Smarcel
439273562Smarcelstatic int
440273562Smarcelrt305x_gpio_attach(device_t dev)
441273562Smarcel{
442273562Smarcel	struct rt305x_gpio_softc *sc = device_get_softc(dev);
443273562Smarcel	int error = 0, i;
444273562Smarcel	uint64_t avlpins = 0;
445273562Smarcel	sc->reset_gpio = DAP1350_RESET_GPIO;
446273562Smarcel
447273562Smarcel	KASSERT((device_get_unit(dev) == 0),
448273562Smarcel	    ("rt305x_gpio_gpio: Only one gpio module supported"));
449273562Smarcel
450273562Smarcel	mtx_init(&sc->gpio_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
451273562Smarcel
452273562Smarcel	/* Map control/status registers. */
453273562Smarcel	sc->gpio_mem_rid = 0;
454273562Smarcel	sc->gpio_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
455273562Smarcel	    &sc->gpio_mem_rid, RF_ACTIVE);
456273562Smarcel
457273562Smarcel	if (sc->gpio_mem_res == NULL) {
458273562Smarcel		device_printf(dev, "couldn't map memory\n");
459273562Smarcel		error = ENXIO;
460273562Smarcel		rt305x_gpio_detach(dev);
461273562Smarcel		return(error);
462273562Smarcel	}
463273562Smarcel
464273562Smarcel	if ((sc->gpio_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
465273562Smarcel	    &sc->gpio_irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
466273562Smarcel		device_printf(dev, "unable to allocate IRQ resource\n");
467273562Smarcel		return (ENXIO);
468273562Smarcel	}
469273562Smarcel
470273562Smarcel	if ((bus_setup_intr(dev, sc->gpio_irq_res, INTR_TYPE_MISC,
471273562Smarcel	    /* rt305x_gpio_filter, */
472273562Smarcel	    rt305x_gpio_intr, NULL, sc, &sc->gpio_ih))) {
473273562Smarcel		device_printf(dev,
474273562Smarcel		    "WARNING: unable to register interrupt handler\n");
475273562Smarcel		return (ENXIO);
476273562Smarcel	}
477273562Smarcel
478273562Smarcel	sc->dev = dev;
479273562Smarcel	avlpins = rt305x_gpio_init(dev);
480273562Smarcel
481273562Smarcel	/* Configure all pins as input */
482273562Smarcel	/* disable interrupts for all pins */
483273562Smarcel	/* TODO */
484273562Smarcel
485273562Smarcel	sc->gpio_npins = NGPIO;
486273562Smarcel	resource_int_value(device_get_name(dev), device_get_unit(dev),
487273562Smarcel	    "pins", &sc->gpio_npins);
488273562Smarcel
489273562Smarcel	for (i = 0; i < sc->gpio_npins; i++) {
490273562Smarcel 		sc->gpio_pins[i].gp_pin = i;
491273562Smarcel 		sc->gpio_pins[i].gp_caps = DEFAULT_CAPS;
492273562Smarcel 		sc->gpio_pins[i].gp_flags = 0;
493273562Smarcel	}
494273562Smarcel
495273562Smarcel	/* Setup reset pin interrupt */
496273562Smarcel	if (TUNABLE_INT_FETCH("reset_gpio", &sc->reset_gpio)) {
497273562Smarcel		device_printf(dev, "\tHinted reset_gpio %d\n", sc->reset_gpio);
498273562Smarcel	}
499273562Smarcel#ifdef	notyet
500273562Smarcel	if (sc->reset_gpio != -1) {
501273562Smarcel		rt305x_gpio_pin_setflags(dev, sc->reset_gpio,
502282100Smarcel		    GPIO_PIN_INPUT|GPIO_PIN_INVOUT|
503273562Smarcel		    GPIO_PIN_INVOUT|GPIO_PIN_REPORT);
504273562Smarcel		device_printf(dev, "\tUse reset_gpio %d\n", sc->reset_gpio);
505273562Smarcel	}
506273562Smarcel#else
507273562Smarcel	if (sc->reset_gpio != -1) {
508273562Smarcel		rt305x_gpio_pin_setflags(dev, sc->reset_gpio,
509273562Smarcel		    GPIO_PIN_INPUT|GPIO_PIN_INVOUT);
510273562Smarcel		device_printf(dev, "\tUse reset_gpio %d\n", sc->reset_gpio);
511273562Smarcel	}
512273562Smarcel#endif
513273562Smarcel
514273562Smarcel	device_add_child(dev, "gpioc", -1);
515273562Smarcel	device_add_child(dev, "gpiobus", -1);
516273562Smarcel
517273562Smarcel	return (bus_generic_attach(dev));
518273562Smarcel}
519273562Smarcel
520273562Smarcelstatic int
521273562Smarcelrt305x_gpio_detach(device_t dev)
522273562Smarcel{
523273562Smarcel	struct rt305x_gpio_softc *sc = device_get_softc(dev);
524273562Smarcel
525273562Smarcel	KASSERT(mtx_initialized(&sc->gpio_mtx), ("gpio mutex not initialized"));
526273562Smarcel
527273562Smarcel	bus_generic_detach(dev);
528273562Smarcel
529273562Smarcel	if (sc->gpio_mem_res)
530273562Smarcel		bus_release_resource(dev, SYS_RES_MEMORY, sc->gpio_mem_rid,
531273562Smarcel		    sc->gpio_mem_res);
532273562Smarcel
533273562Smarcel	mtx_destroy(&sc->gpio_mtx);
534273562Smarcel
535273562Smarcel	return(0);
536273562Smarcel}
537273562Smarcel
538273562Smarcel#ifdef notyet
539273562Smarcelstatic struct resource *
540273562Smarcelrt305x_gpio_alloc_resource(device_t bus, device_t child, int type, int *rid,
541273562Smarcel    u_long start, u_long end, u_long count, u_int flags)
542273562Smarcel{
543273562Smarcel	struct obio_softc		*sc = device_get_softc(bus);
544273562Smarcel	struct resource			*rv;
545273562Smarcel	struct rman			*rm;
546273562Smarcel
547273562Smarcel	switch (type) {
548273562Smarcel	case SYS_RES_GPIO:
549273562Smarcel		rm = &sc->gpio_rman;
550273562Smarcel		break;
551273562Smarcel	default:
552273562Smarcel		printf("%s: unknown resource type %d\n", __func__, type);
553273562Smarcel		return (0);
554273562Smarcel	}
555273562Smarcel
556273562Smarcel	rv = rman_reserve_resource(rm, start, end, count, flags, child);
557273562Smarcel	if (rv == 0) {
558273562Smarcel		printf("%s: could not reserve resource\n", __func__);
559273562Smarcel		return (0);
560273562Smarcel	}
561273562Smarcel
562273562Smarcel	rman_set_rid(rv, *rid);
563273562Smarcel
564273562Smarcel	return (rv);
565273562Smarcel}
566273562Smarcel
567273562Smarcelstatic int
568273562Smarcelrt305x_gpio_activate_resource(device_t bus, device_t child, int type, int rid,
569273562Smarcel    struct resource *r)
570273562Smarcel{
571273562Smarcel
572273562Smarcel	return (rman_activate_resource(r));
573273562Smarcel}
574273562Smarcel
575273562Smarcelstatic int
576273562Smarcelrt305x_gpio_deactivate_resource(device_t bus, device_t child, int type, int rid,
577273562Smarcel    struct resource *r)
578273562Smarcel{
579273562Smarcel
580273562Smarcel	return (rman_deactivate_resource(r));
581273562Smarcel}
582273562Smarcel
583273562Smarcelstatic int
584273562Smarcelrt305x_gpio_release_resource(device_t dev, device_t child, int type,
585273562Smarcel    int rid, struct resource *r)
586273562Smarcel{
587273562Smarcel	rman_release_resource(r);
588273562Smarcel	return (0);
589274672Smarcel}
590273562Smarcel#endif
591273562Smarcel
592273562Smarcelstatic device_method_t rt305x_gpio_methods[] = {
593273562Smarcel	DEVMETHOD(device_probe,		rt305x_gpio_probe),
594273562Smarcel	DEVMETHOD(device_attach,	rt305x_gpio_attach),
595273562Smarcel	DEVMETHOD(device_detach,	rt305x_gpio_detach),
596273562Smarcel
597273562Smarcel	/* GPIO protocol */
598273562Smarcel	DEVMETHOD(gpio_pin_max,		rt305x_gpio_pin_max),
599273562Smarcel	DEVMETHOD(gpio_pin_getname,	rt305x_gpio_pin_getname),
600273562Smarcel	DEVMETHOD(gpio_pin_getflags,	rt305x_gpio_pin_getflags),
601273562Smarcel	DEVMETHOD(gpio_pin_getcaps,	rt305x_gpio_pin_getcaps),
602273562Smarcel	DEVMETHOD(gpio_pin_setflags,	rt305x_gpio_pin_setflags),
603273562Smarcel	DEVMETHOD(gpio_pin_get,		rt305x_gpio_pin_get),
604273562Smarcel	DEVMETHOD(gpio_pin_set,		rt305x_gpio_pin_set),
605273562Smarcel	DEVMETHOD(gpio_pin_toggle,	rt305x_gpio_pin_toggle),
606273562Smarcel	{0, 0},
607273562Smarcel};
608273562Smarcel
609273562Smarcelstatic driver_t rt305x_gpio_driver = {
610273562Smarcel	"gpio",
611273562Smarcel	rt305x_gpio_methods,
612273562Smarcel	sizeof(struct rt305x_gpio_softc),
613273562Smarcel};
614273562Smarcelstatic devclass_t rt305x_gpio_devclass;
615273562Smarcel
616DRIVER_MODULE(rt305x_gpio, obio, rt305x_gpio_driver,
617    rt305x_gpio_devclass, 0, 0);
618