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