wii_gpio.c revision 246655
1/*-
2 * Copyright (C) 2012 Margarida Gouveia
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
21 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26#include <sys/cdefs.h>
27__FBSDID("$FreeBSD: head/sys/powerpc/wii/wii_gpio.c 246655 2013-02-11 08:20:21Z rpaulo $");
28
29#include <sys/param.h>
30#include <sys/systm.h>
31#include <sys/module.h>
32#include <sys/bus.h>
33#include <sys/conf.h>
34#include <sys/kernel.h>
35#include <sys/malloc.h>
36#include <sys/rman.h>
37#include <sys/gpio.h>
38
39#include <machine/bus.h>
40#include <machine/platform.h>
41#include <machine/intr_machdep.h>
42#include <machine/resource.h>
43
44#include <powerpc/wii/wii_gpioreg.h>
45
46#include "gpio_if.h"
47
48struct wiigpio_softc {
49	device_t		 sc_dev;
50	struct resource		*sc_rres;
51	bus_space_tag_t		 sc_bt;
52	bus_space_handle_t	 sc_bh;
53	int			 sc_rrid;
54	struct mtx		 sc_mtx;
55	struct gpio_pin		 sc_pins[WIIGPIO_NPINS];
56};
57
58#define WIIGPIO_LOCK(sc)	mtx_lock(&(sc)->sc_mtx)
59#define WIIGPIO_UNLOCK(sc)	mtx_unlock(&(sc)->sc_mtx)
60
61static int	wiigpio_probe(device_t);
62static int	wiigpio_attach(device_t);
63static int	wiigpio_detach(device_t);
64static int	wiigpio_pin_max(device_t, int *);
65static int	wiigpio_pin_getname(device_t, uint32_t, char *);
66static int	wiigpio_pin_getflags(device_t, uint32_t, uint32_t *);
67static int	wiigpio_pin_setflags(device_t, uint32_t, uint32_t);
68static int	wiigpio_pin_getcaps(device_t, uint32_t, uint32_t *);
69static int	wiigpio_pin_get(device_t, uint32_t, unsigned int *);
70static int	wiigpio_pin_set(device_t, uint32_t, unsigned int);
71static int	wiigpio_pin_toggle(device_t, uint32_t);
72
73static device_method_t wiigpio_methods[] = {
74	/* Device interface */
75	DEVMETHOD(device_probe,		wiigpio_probe),
76	DEVMETHOD(device_attach,	wiigpio_attach),
77	DEVMETHOD(device_detach,	wiigpio_detach),
78
79	/* GPIO protocol */
80	DEVMETHOD(gpio_pin_max,		wiigpio_pin_max),
81	DEVMETHOD(gpio_pin_getname,	wiigpio_pin_getname),
82	DEVMETHOD(gpio_pin_getflags,	wiigpio_pin_getflags),
83	DEVMETHOD(gpio_pin_setflags,	wiigpio_pin_setflags),
84	DEVMETHOD(gpio_pin_getcaps,	wiigpio_pin_getcaps),
85	DEVMETHOD(gpio_pin_get,		wiigpio_pin_get),
86	DEVMETHOD(gpio_pin_set,		wiigpio_pin_set),
87	DEVMETHOD(gpio_pin_toggle,	wiigpio_pin_toggle),
88
89        DEVMETHOD_END
90};
91
92static driver_t wiigpio_driver = {
93	"wiigpio",
94	wiigpio_methods,
95	sizeof(struct wiigpio_softc)
96};
97
98static devclass_t wiigpio_devclass;
99
100DRIVER_MODULE(wiigpio, wiibus, wiigpio_driver, wiigpio_devclass, 0, 0);
101
102static __inline uint32_t
103wiigpio_read(struct wiigpio_softc *sc)
104{
105
106	return (bus_space_read_4(sc->sc_bt, sc->sc_bh, 0));
107}
108
109static __inline void
110wiigpio_write(struct wiigpio_softc *sc, uint32_t reg)
111{
112
113	bus_space_write_4(sc->sc_bt, sc->sc_bh, 0, reg);
114}
115
116static int
117wiigpio_probe(device_t dev)
118{
119        device_set_desc(dev, "Nintendo Wii GPIO");
120
121        return (BUS_PROBE_NOWILDCARD);
122}
123
124static int
125wiigpio_attach(device_t dev)
126{
127	struct wiigpio_softc *sc;
128	int i;
129
130	sc = device_get_softc(dev);
131	sc->sc_dev = dev;
132
133	sc->sc_rrid = 0;
134	sc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
135	    &sc->sc_rrid, RF_ACTIVE);
136	if (sc->sc_rres == NULL) {
137		device_printf(dev, "could not alloc mem resource\n");
138		return (ENXIO);
139	}
140	sc->sc_bt = rman_get_bustag(sc->sc_rres);
141	sc->sc_bh = rman_get_bushandle(sc->sc_rres);
142
143	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
144
145	for (i = 0; i < WIIGPIO_NPINS; i++) {
146		sc->sc_pins[i].gp_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
147		sc->sc_pins[i].gp_pin = i;
148		sc->sc_pins[i].gp_flags = 0;
149		snprintf(sc->sc_pins[i].gp_name, GPIOMAXNAME, "PIN %d", i);
150	}
151
152	device_add_child(dev, "gpioc", device_get_unit(dev));
153	device_add_child(dev, "gpiobus", device_get_unit(dev));
154
155	return (bus_generic_attach(dev));
156}
157
158static int
159wiigpio_detach(device_t dev)
160{
161	struct wiigpio_softc *sc;
162
163	sc = device_get_softc(dev);
164	bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rrid, sc->sc_rres);
165	mtx_destroy(&sc->sc_mtx);
166
167	return (0);
168}
169
170static int
171wiigpio_pin_max(device_t dev, int *maxpin)
172{
173
174	*maxpin = WIIGPIO_NPINS - 1;
175
176	return (0);
177}
178
179static int
180wiigpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
181{
182	struct wiigpio_softc *sc;
183
184	if (pin >= WIIGPIO_NPINS)
185		return (EINVAL);
186	sc = device_get_softc(dev);
187	*caps = sc->sc_pins[pin].gp_caps;
188
189	return (0);
190}
191
192static int
193wiigpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
194{
195	struct wiigpio_softc *sc;
196	uint32_t reg;
197
198	if (pin >= WIIGPIO_NPINS)
199		return (EINVAL);
200	sc = device_get_softc(dev);
201	WIIGPIO_LOCK(sc);
202	reg = wiigpio_read(sc);
203	*val = !!(reg & (1 << pin));
204	WIIGPIO_UNLOCK(sc);
205
206	return (0);
207}
208
209static int
210wiigpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
211{
212	struct wiigpio_softc *sc;
213	uint32_t reg, pinmask = 1 << pin;
214
215	if (pin >= WIIGPIO_NPINS)
216		return (EINVAL);
217	sc = device_get_softc(dev);
218	WIIGPIO_LOCK(sc);
219	reg = wiigpio_read(sc) & ~pinmask;
220	if (value)
221		reg |= pinmask;
222	wiigpio_write(sc, reg);
223	WIIGPIO_UNLOCK(sc);
224
225	return (0);
226}
227
228static int
229wiigpio_pin_toggle(device_t dev, uint32_t pin)
230{
231	struct wiigpio_softc *sc;
232	uint32_t val, pinmask = 1 << pin;
233
234	sc = device_get_softc(dev);
235	WIIGPIO_LOCK(sc);
236	val = wiigpio_read(sc) & pinmask;
237	if (val)
238		wiigpio_write(sc, wiigpio_read(sc) & ~pinmask);
239	else
240		wiigpio_write(sc, wiigpio_read(sc) | pinmask);
241	WIIGPIO_UNLOCK(sc);
242
243	return (0);
244}
245
246static int
247wiigpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
248{
249	struct wiigpio_softc *sc;
250
251	if (pin >= WIIGPIO_NPINS)
252		return (EINVAL);
253	sc = device_get_softc(dev);
254	WIIGPIO_LOCK(sc);
255	sc->sc_pins[pin].gp_flags = flags;
256	WIIGPIO_UNLOCK(sc);
257
258	return (0);
259}
260
261static int
262wiigpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
263{
264	struct wiigpio_softc *sc;
265
266	if (pin >= WIIGPIO_NPINS)
267		return (EINVAL);
268	sc = device_get_softc(dev);
269	WIIGPIO_LOCK(sc);
270	*flags = sc->sc_pins[pin].gp_flags;
271	WIIGPIO_UNLOCK(sc);
272
273	return (0);
274}
275
276static int
277wiigpio_pin_getname(device_t dev, uint32_t pin, char *name)
278{
279	struct wiigpio_softc *sc;
280
281	if (pin >= WIIGPIO_NPINS)
282		return (EINVAL);
283	sc = device_get_softc(dev);
284	WIIGPIO_LOCK(sc);
285	memcpy(name, sc->sc_pins[pin].gp_name, GPIOMAXNAME);
286	WIIGPIO_UNLOCK(sc);
287
288	return (0);
289}
290