]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/powerpc/wii/wii_gpio.c
Update to 9.8.4-P1.
[FreeBSD/FreeBSD.git] / sys / powerpc / wii / wii_gpio.c
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$");
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
48 struct 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
61 static int      wiigpio_probe(device_t);
62 static int      wiigpio_attach(device_t);
63 static int      wiigpio_detach(device_t);
64 static int      wiigpio_pin_max(device_t, int *);
65 static int      wiigpio_pin_getname(device_t, uint32_t, char *);
66 static int      wiigpio_pin_getflags(device_t, uint32_t, uint32_t *);
67 static int      wiigpio_pin_setflags(device_t, uint32_t, uint32_t);
68 static int      wiigpio_pin_getcaps(device_t, uint32_t, uint32_t *);
69 static int      wiigpio_pin_get(device_t, uint32_t, unsigned int *);
70 static int      wiigpio_pin_set(device_t, uint32_t, unsigned int);
71 static int      wiigpio_pin_toggle(device_t, uint32_t);
72
73 static 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         { 0, 0 },
90 };
91
92 static driver_t wiigpio_driver = {
93         "wiigpio",
94         wiigpio_methods,
95         sizeof(struct wiigpio_softc)
96 };
97
98 static devclass_t wiigpio_devclass;
99
100 DRIVER_MODULE(wiigpio, wiibus, wiigpio_driver, wiigpio_devclass, 0, 0);
101
102 static __inline uint32_t
103 wiigpio_read(struct wiigpio_softc *sc)
104 {
105
106         return (bus_space_read_4(sc->sc_bt, sc->sc_bh, 0));
107 }
108
109 static __inline void
110 wiigpio_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
116 static int
117 wiigpio_probe(device_t dev)
118 {
119         device_set_desc(dev, "Nintendo Wii GPIO");
120
121         return (BUS_PROBE_NOWILDCARD);
122 }
123
124 static int
125 wiigpio_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
158 static int
159 wiigpio_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
170 static int
171 wiigpio_pin_max(device_t dev, int *maxpin)
172 {
173         
174         *maxpin = WIIGPIO_NPINS - 1;
175
176         return (0);
177 }
178
179 static int
180 wiigpio_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
192 static int
193 wiigpio_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
209 static int
210 wiigpio_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
228 static int
229 wiigpio_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
246 static int
247 wiigpio_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
261 static int
262 wiigpio_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
276 static int
277 wiigpio_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 }