1258057Sbr/*- 2258057Sbr * Copyright (c) 2013 Ruslan Bukin <br@bsdpad.com> 3258057Sbr * All rights reserved. 4258057Sbr * 5258057Sbr * Redistribution and use in source and binary forms, with or without 6258057Sbr * modification, are permitted provided that the following conditions 7258057Sbr * are met: 8258057Sbr * 1. Redistributions of source code must retain the above copyright 9258057Sbr * notice, this list of conditions and the following disclaimer. 10258057Sbr * 2. Redistributions in binary form must reproduce the above copyright 11258057Sbr * notice, this list of conditions and the following disclaimer in the 12258057Sbr * documentation and/or other materials provided with the distribution. 13258057Sbr * 14258057Sbr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15258057Sbr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16258057Sbr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17258057Sbr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18258057Sbr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19258057Sbr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20258057Sbr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21258057Sbr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22258057Sbr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23258057Sbr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24258057Sbr * SUCH DAMAGE. 25258057Sbr */ 26258057Sbr 27258057Sbr/* 28258057Sbr * Vybrid Family General-Purpose Input/Output (GPIO) 29258057Sbr * Chapter 7, Vybrid Reference Manual, Rev. 5, 07/2013 30258057Sbr */ 31258057Sbr 32258057Sbr#include <sys/cdefs.h> 33258057Sbr__FBSDID("$FreeBSD: releng/11.0/sys/arm/freescale/vybrid/vf_gpio.c 281085 2015-04-04 21:34:26Z andrew $"); 34258057Sbr 35258057Sbr#include <sys/param.h> 36258057Sbr#include <sys/systm.h> 37258057Sbr#include <sys/bus.h> 38258057Sbr#include <sys/kernel.h> 39258057Sbr#include <sys/module.h> 40258057Sbr#include <sys/malloc.h> 41258057Sbr#include <sys/rman.h> 42258057Sbr#include <sys/timeet.h> 43258057Sbr#include <sys/timetc.h> 44258057Sbr#include <sys/watchdog.h> 45258057Sbr#include <sys/mutex.h> 46258057Sbr#include <sys/gpio.h> 47258057Sbr 48258057Sbr#include <dev/fdt/fdt_common.h> 49277996Sloos#include <dev/gpio/gpiobusvar.h> 50258057Sbr#include <dev/ofw/openfirm.h> 51258057Sbr#include <dev/ofw/ofw_bus.h> 52258057Sbr#include <dev/ofw/ofw_bus_subr.h> 53258057Sbr 54258057Sbr#include <machine/bus.h> 55258057Sbr#include <machine/cpu.h> 56258057Sbr#include <machine/intr.h> 57258057Sbr 58258057Sbr#include "gpio_if.h" 59258057Sbr 60258057Sbr#include <arm/freescale/vybrid/vf_common.h> 61262885Sbr#include <arm/freescale/vybrid/vf_port.h> 62258057Sbr 63258057Sbr#define GPIO_PDOR(n) (0x00 + 0x40 * (n >> 5)) 64258057Sbr#define GPIO_PSOR(n) (0x04 + 0x40 * (n >> 5)) 65258057Sbr#define GPIO_PCOR(n) (0x08 + 0x40 * (n >> 5)) 66258057Sbr#define GPIO_PTOR(n) (0x0C + 0x40 * (n >> 5)) 67258057Sbr#define GPIO_PDIR(n) (0x10 + 0x40 * (n >> 5)) 68258057Sbr 69258057Sbr#define GPIO_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) 70258057Sbr#define GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) 71258057Sbr 72258057Sbr#define DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT) 73258057Sbr 74258057Sbr/* 75258057Sbr * GPIO interface 76258057Sbr */ 77277996Sloosstatic device_t vf_gpio_get_bus(device_t); 78258057Sbrstatic int vf_gpio_pin_max(device_t, int *); 79258057Sbrstatic int vf_gpio_pin_getcaps(device_t, uint32_t, uint32_t *); 80258057Sbrstatic int vf_gpio_pin_getname(device_t, uint32_t, char *); 81258057Sbrstatic int vf_gpio_pin_getflags(device_t, uint32_t, uint32_t *); 82258057Sbrstatic int vf_gpio_pin_setflags(device_t, uint32_t, uint32_t); 83258057Sbrstatic int vf_gpio_pin_set(device_t, uint32_t, unsigned int); 84258057Sbrstatic int vf_gpio_pin_get(device_t, uint32_t, unsigned int *); 85258057Sbrstatic int vf_gpio_pin_toggle(device_t, uint32_t pin); 86258057Sbr 87258057Sbrstruct vf_gpio_softc { 88262885Sbr struct resource *res[1]; 89258057Sbr bus_space_tag_t bst; 90258057Sbr bus_space_handle_t bsh; 91258057Sbr 92277996Sloos device_t sc_busdev; 93258057Sbr struct mtx sc_mtx; 94258057Sbr int gpio_npins; 95258057Sbr struct gpio_pin gpio_pins[NGPIO]; 96258057Sbr}; 97258057Sbr 98258057Sbrstruct vf_gpio_softc *gpio_sc; 99258057Sbr 100258057Sbrstatic struct resource_spec vf_gpio_spec[] = { 101258057Sbr { SYS_RES_MEMORY, 0, RF_ACTIVE }, 102258057Sbr { -1, 0 } 103258057Sbr}; 104258057Sbr 105258057Sbrstatic int 106258057Sbrvf_gpio_probe(device_t dev) 107258057Sbr{ 108258057Sbr 109261410Sian if (!ofw_bus_status_okay(dev)) 110261410Sian return (ENXIO); 111261410Sian 112258057Sbr if (!ofw_bus_is_compatible(dev, "fsl,mvf600-gpio")) 113258057Sbr return (ENXIO); 114258057Sbr 115258057Sbr device_set_desc(dev, "Vybrid Family GPIO Unit"); 116258057Sbr return (BUS_PROBE_DEFAULT); 117258057Sbr} 118258057Sbr 119258057Sbrstatic int 120258057Sbrvf_gpio_attach(device_t dev) 121258057Sbr{ 122258057Sbr struct vf_gpio_softc *sc; 123262885Sbr int i; 124258057Sbr 125258057Sbr sc = device_get_softc(dev); 126258057Sbr mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 127258057Sbr 128258057Sbr if (bus_alloc_resources(dev, vf_gpio_spec, sc->res)) { 129258057Sbr device_printf(dev, "could not allocate resources\n"); 130277968Sloos mtx_destroy(&sc->sc_mtx); 131258057Sbr return (ENXIO); 132258057Sbr } 133258057Sbr 134258057Sbr /* Memory interface */ 135258057Sbr sc->bst = rman_get_bustag(sc->res[0]); 136258057Sbr sc->bsh = rman_get_bushandle(sc->res[0]); 137258057Sbr 138262885Sbr gpio_sc = sc; 139262885Sbr 140258057Sbr sc->gpio_npins = NGPIO; 141258057Sbr 142258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 143258057Sbr sc->gpio_pins[i].gp_pin = i; 144258057Sbr sc->gpio_pins[i].gp_caps = DEFAULT_CAPS; 145258057Sbr sc->gpio_pins[i].gp_flags = 146258057Sbr (READ4(sc, GPIO_PDOR(i)) & (1 << (i % 32))) ? 147258057Sbr GPIO_PIN_OUTPUT: GPIO_PIN_INPUT; 148258057Sbr snprintf(sc->gpio_pins[i].gp_name, GPIOMAXNAME, 149258057Sbr "vf_gpio%d.%d", device_get_unit(dev), i); 150258057Sbr } 151258057Sbr 152277996Sloos sc->sc_busdev = gpiobus_attach_bus(dev); 153277996Sloos if (sc->sc_busdev == NULL) { 154277996Sloos bus_release_resources(dev, vf_gpio_spec, sc->res); 155277996Sloos mtx_destroy(&sc->sc_mtx); 156277996Sloos return (ENXIO); 157277996Sloos } 158258057Sbr 159277996Sloos return (0); 160258057Sbr} 161258057Sbr 162277996Sloosstatic device_t 163277996Sloosvf_gpio_get_bus(device_t dev) 164277996Sloos{ 165277996Sloos struct vf_gpio_softc *sc; 166277996Sloos 167277996Sloos sc = device_get_softc(dev); 168277996Sloos 169277996Sloos return (sc->sc_busdev); 170277996Sloos} 171277996Sloos 172258057Sbrstatic int 173258057Sbrvf_gpio_pin_max(device_t dev, int *maxpin) 174258057Sbr{ 175258057Sbr 176258057Sbr *maxpin = NGPIO - 1; 177258057Sbr return (0); 178258057Sbr} 179258057Sbr 180258057Sbrstatic int 181258057Sbrvf_gpio_pin_getname(device_t dev, uint32_t pin, char *name) 182258057Sbr{ 183258057Sbr struct vf_gpio_softc *sc; 184258057Sbr int i; 185258057Sbr 186258057Sbr sc = device_get_softc(dev); 187258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 188258057Sbr if (sc->gpio_pins[i].gp_pin == pin) 189258057Sbr break; 190258057Sbr } 191258057Sbr 192258057Sbr if (i >= sc->gpio_npins) 193258057Sbr return (EINVAL); 194258057Sbr 195258057Sbr GPIO_LOCK(sc); 196258057Sbr memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME); 197258057Sbr GPIO_UNLOCK(sc); 198258057Sbr 199258057Sbr return (0); 200258057Sbr} 201258057Sbr 202258057Sbrstatic int 203258057Sbrvf_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) 204258057Sbr{ 205258057Sbr struct vf_gpio_softc *sc; 206258057Sbr int i; 207258057Sbr 208258057Sbr sc = device_get_softc(dev); 209258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 210258057Sbr if (sc->gpio_pins[i].gp_pin == pin) 211258057Sbr break; 212258057Sbr } 213258057Sbr 214258057Sbr if (i >= sc->gpio_npins) 215258057Sbr return (EINVAL); 216258057Sbr 217258057Sbr GPIO_LOCK(sc); 218258057Sbr *caps = sc->gpio_pins[i].gp_caps; 219258057Sbr GPIO_UNLOCK(sc); 220258057Sbr 221258057Sbr return (0); 222258057Sbr} 223258057Sbr 224258057Sbrstatic int 225258057Sbrvf_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) 226258057Sbr{ 227258057Sbr struct vf_gpio_softc *sc; 228258057Sbr int i; 229258057Sbr 230258057Sbr sc = device_get_softc(dev); 231258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 232258057Sbr if (sc->gpio_pins[i].gp_pin == pin) 233258057Sbr break; 234258057Sbr } 235258057Sbr 236258057Sbr if (i >= sc->gpio_npins) 237258057Sbr return (EINVAL); 238258057Sbr 239258057Sbr GPIO_LOCK(sc); 240258057Sbr *flags = sc->gpio_pins[i].gp_flags; 241258057Sbr GPIO_UNLOCK(sc); 242258057Sbr 243258057Sbr return (0); 244258057Sbr} 245258057Sbr 246258057Sbrstatic int 247258057Sbrvf_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) 248258057Sbr{ 249258057Sbr struct vf_gpio_softc *sc; 250258057Sbr int i; 251258057Sbr 252258057Sbr sc = device_get_softc(dev); 253258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 254258057Sbr if (sc->gpio_pins[i].gp_pin == pin) 255258057Sbr break; 256258057Sbr } 257258057Sbr 258258057Sbr if (i >= sc->gpio_npins) 259258057Sbr return (EINVAL); 260258057Sbr 261258057Sbr GPIO_LOCK(sc); 262266119Sbr *val = (READ4(sc, GPIO_PDIR(i)) & (1 << (i % 32))) ? 1 : 0; 263258057Sbr GPIO_UNLOCK(sc); 264258057Sbr 265258057Sbr return (0); 266258057Sbr} 267258057Sbr 268258057Sbrstatic int 269258057Sbrvf_gpio_pin_toggle(device_t dev, uint32_t pin) 270258057Sbr{ 271258057Sbr struct vf_gpio_softc *sc; 272258057Sbr int i; 273258057Sbr 274258057Sbr sc = device_get_softc(dev); 275258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 276258057Sbr if (sc->gpio_pins[i].gp_pin == pin) 277258057Sbr break; 278258057Sbr } 279258057Sbr 280258057Sbr if (i >= sc->gpio_npins) 281258057Sbr return (EINVAL); 282258057Sbr 283258057Sbr GPIO_LOCK(sc); 284258057Sbr WRITE4(sc, GPIO_PTOR(i), (1 << (i % 32))); 285258057Sbr GPIO_UNLOCK(sc); 286258057Sbr 287258057Sbr return (0); 288258057Sbr} 289258057Sbr 290258057Sbr 291258057Sbrstatic void 292258057Sbrvf_gpio_pin_configure(struct vf_gpio_softc *sc, struct gpio_pin *pin, 293258057Sbr unsigned int flags) 294258057Sbr{ 295258057Sbr 296258057Sbr GPIO_LOCK(sc); 297258057Sbr 298258057Sbr /* 299258057Sbr * Manage input/output 300258057Sbr */ 301258057Sbr if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) { 302258057Sbr pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT); 303258057Sbr if (flags & GPIO_PIN_OUTPUT) { 304258057Sbr pin->gp_flags |= GPIO_PIN_OUTPUT; 305258057Sbr 306258057Sbr } else { 307258057Sbr pin->gp_flags |= GPIO_PIN_INPUT; 308258057Sbr WRITE4(sc, GPIO_PCOR(pin->gp_pin), 309258057Sbr (1 << (pin->gp_pin % 32))); 310258057Sbr } 311258057Sbr } 312258057Sbr 313258057Sbr GPIO_UNLOCK(sc); 314258057Sbr} 315258057Sbr 316258057Sbr 317258057Sbrstatic int 318258057Sbrvf_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) 319258057Sbr{ 320258057Sbr struct vf_gpio_softc *sc; 321258057Sbr int i; 322258057Sbr 323258057Sbr sc = device_get_softc(dev); 324258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 325258057Sbr if (sc->gpio_pins[i].gp_pin == pin) 326258057Sbr break; 327258057Sbr } 328258057Sbr 329258057Sbr if (i >= sc->gpio_npins) 330258057Sbr return (EINVAL); 331258057Sbr 332258057Sbr vf_gpio_pin_configure(sc, &sc->gpio_pins[i], flags); 333258057Sbr 334258057Sbr return (0); 335258057Sbr} 336258057Sbr 337258057Sbrstatic int 338258057Sbrvf_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) 339258057Sbr{ 340258057Sbr struct vf_gpio_softc *sc; 341258057Sbr int i; 342258057Sbr 343258057Sbr sc = device_get_softc(dev); 344258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 345258057Sbr if (sc->gpio_pins[i].gp_pin == pin) 346258057Sbr break; 347258057Sbr } 348258057Sbr 349258057Sbr if (i >= sc->gpio_npins) 350258057Sbr return (EINVAL); 351258057Sbr 352258057Sbr GPIO_LOCK(sc); 353258057Sbr if (value) 354258057Sbr WRITE4(sc, GPIO_PSOR(i), (1 << (i % 32))); 355258057Sbr else 356258057Sbr WRITE4(sc, GPIO_PCOR(i), (1 << (i % 32))); 357258057Sbr GPIO_UNLOCK(sc); 358258057Sbr 359258057Sbr return (0); 360258057Sbr} 361258057Sbr 362258057Sbrstatic device_method_t vf_gpio_methods[] = { 363258057Sbr DEVMETHOD(device_probe, vf_gpio_probe), 364258057Sbr DEVMETHOD(device_attach, vf_gpio_attach), 365258057Sbr 366258057Sbr /* GPIO protocol */ 367277996Sloos DEVMETHOD(gpio_get_bus, vf_gpio_get_bus), 368258057Sbr DEVMETHOD(gpio_pin_max, vf_gpio_pin_max), 369258057Sbr DEVMETHOD(gpio_pin_getname, vf_gpio_pin_getname), 370258057Sbr DEVMETHOD(gpio_pin_getcaps, vf_gpio_pin_getcaps), 371258057Sbr DEVMETHOD(gpio_pin_getflags, vf_gpio_pin_getflags), 372258057Sbr DEVMETHOD(gpio_pin_get, vf_gpio_pin_get), 373258057Sbr DEVMETHOD(gpio_pin_toggle, vf_gpio_pin_toggle), 374258057Sbr DEVMETHOD(gpio_pin_setflags, vf_gpio_pin_setflags), 375258057Sbr DEVMETHOD(gpio_pin_set, vf_gpio_pin_set), 376258057Sbr { 0, 0 } 377258057Sbr}; 378258057Sbr 379258057Sbrstatic driver_t vf_gpio_driver = { 380258057Sbr "gpio", 381258057Sbr vf_gpio_methods, 382258057Sbr sizeof(struct vf_gpio_softc), 383258057Sbr}; 384258057Sbr 385258057Sbrstatic devclass_t vf_gpio_devclass; 386258057Sbr 387258057SbrDRIVER_MODULE(vf_gpio, simplebus, vf_gpio_driver, vf_gpio_devclass, 0, 0); 388