1169425Sgnn/*-
2169425Sgnn * Copyright (C) 2012 Margarida Gouveia
3169425Sgnn * All rights reserved.
4169425Sgnn *
5169425Sgnn * Redistribution and use in source and binary forms, with or without
6169425Sgnn * modification, are permitted provided that the following conditions
7169425Sgnn * are met:
8169425Sgnn * 1. Redistributions of source code must retain the above copyright
9169425Sgnn *    notice, this list of conditions and the following disclaimer.
10169425Sgnn * 2. Redistributions in binary form must reproduce the above copyright
11169425Sgnn *    notice, this list of conditions and the following disclaimer in the
12169425Sgnn *    documentation and/or other materials provided with the distribution.
13169425Sgnn *
14169425Sgnn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15169425Sgnn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16169425Sgnn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17169425Sgnn * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18169425Sgnn * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19169425Sgnn * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20169425Sgnn * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
21169425Sgnn * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22169425Sgnn * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23169425Sgnn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24169425Sgnn * SUCH DAMAGE.
25169425Sgnn */
26169425Sgnn#include <sys/cdefs.h>
27169425Sgnn__FBSDID("$FreeBSD$");
28169425Sgnn
29169425Sgnn#include <sys/param.h>
30169425Sgnn#include <sys/systm.h>
31169425Sgnn#include <sys/module.h>
32169425Sgnn#include <sys/bus.h>
33169425Sgnn#include <sys/conf.h>
34169425Sgnn#include <sys/kernel.h>
35169425Sgnn#include <sys/malloc.h>
36169425Sgnn#include <sys/rman.h>
37169425Sgnn#include <sys/gpio.h>
38169425Sgnn#include <sys/reboot.h>
39169425Sgnn
40169425Sgnn#include <machine/bus.h>
41169425Sgnn#include <machine/platform.h>
42169425Sgnn#include <machine/intr_machdep.h>
43169425Sgnn#include <machine/resource.h>
44169425Sgnn
45169425Sgnn#include <powerpc/wii/wii_gpioreg.h>
46169425Sgnn
47169425Sgnn#include "gpio_if.h"
48169425Sgnn
49169425Sgnnstruct wiigpio_softc {
50169425Sgnn	device_t		 sc_dev;
51169425Sgnn	struct resource		*sc_rres;
52169425Sgnn	bus_space_tag_t		 sc_bt;
53169425Sgnn	bus_space_handle_t	 sc_bh;
54169425Sgnn	int			 sc_rrid;
55169425Sgnn	struct mtx		 sc_mtx;
56169425Sgnn	struct gpio_pin		 sc_pins[WIIGPIO_NPINS];
57169425Sgnn};
58169425Sgnn
59
60#define	WIIGPIO_PINBANK(_p)	((_p) / (WIIGPIO_NPINS / 2))
61#define	WIIGPIO_PINMASK(_p)	(1 << ((_p) % (WIIGPIO_NPINS / 2)))
62#define WIIGPIO_LOCK(sc)	mtx_lock(&(sc)->sc_mtx)
63#define WIIGPIO_UNLOCK(sc)	mtx_unlock(&(sc)->sc_mtx)
64
65static int	wiigpio_probe(device_t);
66static int	wiigpio_attach(device_t);
67static int	wiigpio_detach(device_t);
68static int	wiigpio_pin_max(device_t, int *);
69static int	wiigpio_pin_getname(device_t, uint32_t, char *);
70static int	wiigpio_pin_getflags(device_t, uint32_t, uint32_t *);
71static int	wiigpio_pin_setflags(device_t, uint32_t, uint32_t);
72static int	wiigpio_pin_getcaps(device_t, uint32_t, uint32_t *);
73static int	wiigpio_pin_get(device_t, uint32_t, unsigned int *);
74static int	wiigpio_pin_set(device_t, uint32_t, unsigned int);
75static int	wiigpio_pin_toggle(device_t, uint32_t);
76static void	wiigpio_shutdown(void *, int);
77
78static device_method_t wiigpio_methods[] = {
79	/* Device interface */
80	DEVMETHOD(device_probe,		wiigpio_probe),
81	DEVMETHOD(device_attach,	wiigpio_attach),
82	DEVMETHOD(device_detach,	wiigpio_detach),
83
84	/* GPIO protocol */
85	DEVMETHOD(gpio_pin_max,		wiigpio_pin_max),
86	DEVMETHOD(gpio_pin_getname,	wiigpio_pin_getname),
87	DEVMETHOD(gpio_pin_getflags,	wiigpio_pin_getflags),
88	DEVMETHOD(gpio_pin_setflags,	wiigpio_pin_setflags),
89	DEVMETHOD(gpio_pin_getcaps,	wiigpio_pin_getcaps),
90	DEVMETHOD(gpio_pin_get,		wiigpio_pin_get),
91	DEVMETHOD(gpio_pin_set,		wiigpio_pin_set),
92	DEVMETHOD(gpio_pin_toggle,	wiigpio_pin_toggle),
93
94        DEVMETHOD_END
95};
96
97static driver_t wiigpio_driver = {
98	"wiigpio",
99	wiigpio_methods,
100	sizeof(struct wiigpio_softc)
101};
102
103static devclass_t wiigpio_devclass;
104
105DRIVER_MODULE(wiigpio, wiibus, wiigpio_driver, wiigpio_devclass, 0, 0);
106
107static __inline uint32_t
108wiigpio_read(struct wiigpio_softc *sc, int n)
109{
110
111	return (bus_space_read_4(sc->sc_bt, sc->sc_bh, n * 0x20));
112}
113
114static __inline void
115wiigpio_write(struct wiigpio_softc *sc, int n, uint32_t reg)
116{
117
118	bus_space_write_4(sc->sc_bt, sc->sc_bh, n * 0x20, reg);
119}
120
121static __inline uint32_t
122wiigpio_dir_read(struct wiigpio_softc *sc, int n)
123{
124
125	return (bus_space_read_4(sc->sc_bt, sc->sc_bh, n * 0x20 + 4));
126}
127
128static __inline void
129wiigpio_dir_write(struct wiigpio_softc *sc, int n, uint32_t reg)
130{
131
132	bus_space_write_4(sc->sc_bt, sc->sc_bh, n * 0x20 + 4, reg);
133}
134
135static int
136wiigpio_probe(device_t dev)
137{
138        device_set_desc(dev, "Nintendo Wii GPIO");
139
140        return (BUS_PROBE_NOWILDCARD);
141}
142
143static int
144wiigpio_attach(device_t dev)
145{
146	struct wiigpio_softc *sc;
147	int i;
148	uint32_t d;
149
150	sc = device_get_softc(dev);
151	sc->sc_dev = dev;
152	sc->sc_rrid = 0;
153	sc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
154	    &sc->sc_rrid, RF_ACTIVE);
155	if (sc->sc_rres == NULL) {
156		device_printf(dev, "could not alloc mem resource\n");
157		return (ENXIO);
158	}
159	sc->sc_bt = rman_get_bustag(sc->sc_rres);
160	sc->sc_bh = rman_get_bushandle(sc->sc_rres);
161	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
162#ifdef WIIGPIO_DEBUG
163	device_printf(dev, "dir bank0=0x%08x bank1=0x%08x\n",
164	    wiigpio_dir_read(sc, 0), wiigpio_dir_read(sc, 1));
165	device_printf(dev, "val bank0=0x%08x bank1=0x%08x\n",
166	    wiigpio_read(sc, 0), wiigpio_read(sc, 1));
167#endif
168	for (i = 0; i < WIIGPIO_NPINS; i++) {
169		sc->sc_pins[i].gp_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
170		sc->sc_pins[i].gp_pin = i;
171		d = wiigpio_dir_read(sc, WIIGPIO_PINBANK(i));
172		if (d & WIIGPIO_PINMASK(i))
173			sc->sc_pins[i].gp_flags = GPIO_PIN_OUTPUT;
174		else
175			sc->sc_pins[i].gp_flags = GPIO_PIN_INPUT;
176		snprintf(sc->sc_pins[i].gp_name, GPIOMAXNAME, "PIN %d", i);
177#ifdef WIIGPIO_DEBUG
178		device_printf(dev, "PIN %d state %d flag %s\n", i,
179		    wiigpio_read(sc, WIIGPIO_PINBANK(i)) >>
180			(i % (WIIGPIO_NPINS / 2)) & 1,
181		    sc->sc_pins[i].gp_flags == GPIO_PIN_INPUT ?
182		    "GPIO_PIN_INPUT" : "GPIO_PIN_OUTPUT");
183#endif
184	}
185	device_add_child(dev, "gpioc", device_get_unit(dev));
186	device_add_child(dev, "gpiobus", device_get_unit(dev));
187	/*
188	 * We will be responsible for powering off the system.
189	 */
190	EVENTHANDLER_REGISTER(shutdown_final, wiigpio_shutdown, dev,
191	    SHUTDOWN_PRI_LAST);
192
193	return (bus_generic_attach(dev));
194}
195
196static int
197wiigpio_detach(device_t dev)
198{
199	struct wiigpio_softc *sc;
200
201	sc = device_get_softc(dev);
202	bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rrid, sc->sc_rres);
203	mtx_destroy(&sc->sc_mtx);
204
205	return (0);
206}
207
208static int
209wiigpio_pin_max(device_t dev, int *maxpin)
210{
211
212	*maxpin = WIIGPIO_NPINS - 1;
213
214	return (0);
215}
216
217static int
218wiigpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
219{
220	struct wiigpio_softc *sc;
221
222	if (pin >= WIIGPIO_NPINS)
223		return (EINVAL);
224	sc = device_get_softc(dev);
225	*caps = sc->sc_pins[pin].gp_caps;
226
227	return (0);
228}
229
230static int
231wiigpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
232{
233	struct wiigpio_softc *sc;
234	uint32_t reg;
235
236	if (pin >= WIIGPIO_NPINS)
237		return (EINVAL);
238	sc = device_get_softc(dev);
239	WIIGPIO_LOCK(sc);
240	reg = wiigpio_read(sc, WIIGPIO_PINBANK(pin));
241	*val = !!(reg & WIIGPIO_PINMASK(pin));
242	WIIGPIO_UNLOCK(sc);
243
244	return (0);
245}
246
247static int
248wiigpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
249{
250	struct wiigpio_softc *sc;
251	uint32_t reg, pinbank, pinmask;
252
253	if (pin >= WIIGPIO_NPINS)
254		return (EINVAL);
255	sc = device_get_softc(dev);
256	pinbank = WIIGPIO_PINBANK(pin);
257	pinmask = WIIGPIO_PINMASK(pin);
258	WIIGPIO_LOCK(sc);
259	reg = wiigpio_read(sc, pinbank) & ~pinmask;
260	if (value)
261		reg |= pinmask;
262	wiigpio_write(sc, pinbank, reg);
263	WIIGPIO_UNLOCK(sc);
264
265	return (0);
266}
267
268static int
269wiigpio_pin_toggle(device_t dev, uint32_t pin)
270{
271	struct wiigpio_softc *sc;
272	uint32_t val, pinbank, pinmask;
273
274	if (pin >= WIIGPIO_NPINS)
275		return (EINVAL);
276	sc = device_get_softc(dev);
277	pinbank = WIIGPIO_PINBANK(pin);
278	pinmask = WIIGPIO_PINMASK(pin);
279	WIIGPIO_LOCK(sc);
280	val = wiigpio_read(sc, pinbank);
281	if (val & pinmask)
282		wiigpio_write(sc, pinbank, val & ~pinmask);
283	else
284		wiigpio_write(sc, pinbank, val | pinmask);
285	WIIGPIO_UNLOCK(sc);
286
287	return (0);
288}
289
290static int
291wiigpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
292{
293	struct wiigpio_softc *sc;
294	uint32_t reg, pinbank, pinmask;
295
296	if (pin >= WIIGPIO_NPINS)
297		return (EINVAL);
298	if ((flags & ~(GPIO_PIN_OUTPUT|GPIO_PIN_INPUT)) != 0)
299		return (EINVAL);
300	if ((flags & (GPIO_PIN_OUTPUT|GPIO_PIN_INPUT)) ==
301	    (GPIO_PIN_OUTPUT|GPIO_PIN_INPUT))
302		return (EINVAL);
303	sc = device_get_softc(dev);
304	pinbank = WIIGPIO_PINBANK(pin);
305	pinmask = WIIGPIO_PINMASK(pin);
306	WIIGPIO_LOCK(sc);
307	reg = wiigpio_dir_read(sc, WIIGPIO_PINBANK(pin));
308	if (flags & GPIO_PIN_OUTPUT)
309		wiigpio_dir_write(sc, pinbank, reg | pinmask);
310	else
311		wiigpio_dir_write(sc, pinbank, reg & ~pinmask);
312	sc->sc_pins[pin].gp_flags = flags;
313	WIIGPIO_UNLOCK(sc);
314
315	return (0);
316}
317
318static int
319wiigpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
320{
321	struct wiigpio_softc *sc;
322
323	if (pin >= WIIGPIO_NPINS)
324		return (EINVAL);
325	sc = device_get_softc(dev);
326	WIIGPIO_LOCK(sc);
327	*flags = sc->sc_pins[pin].gp_flags;
328	WIIGPIO_UNLOCK(sc);
329
330	return (0);
331}
332
333static int
334wiigpio_pin_getname(device_t dev, uint32_t pin, char *name)
335{
336	struct wiigpio_softc *sc;
337
338	if (pin >= WIIGPIO_NPINS)
339		return (EINVAL);
340	sc = device_get_softc(dev);
341	WIIGPIO_LOCK(sc);
342	memcpy(name, sc->sc_pins[pin].gp_name, GPIOMAXNAME);
343	WIIGPIO_UNLOCK(sc);
344
345	return (0);
346}
347
348static void
349wiigpio_shutdown(void *xdev, int howto)
350{
351	device_t dev;
352
353	if (!(howto & RB_POWEROFF))
354		return;
355	dev = (device_t)xdev;
356	wiigpio_pin_setflags(dev, WIIGPIO_POWEROFF_PIN, GPIO_PIN_OUTPUT);
357	wiigpio_pin_set(dev, WIIGPIO_POWEROFF_PIN, 1);
358}
359