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