vf_gpio.c revision 277996
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: head/sys/arm/freescale/vybrid/vf_gpio.c 277996 2015-01-31 19:32:14Z loos $"); 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/fdt.h> 56258057Sbr#include <machine/cpu.h> 57258057Sbr#include <machine/intr.h> 58258057Sbr 59258057Sbr#include "gpio_if.h" 60258057Sbr 61258057Sbr#include <arm/freescale/vybrid/vf_common.h> 62262885Sbr#include <arm/freescale/vybrid/vf_port.h> 63258057Sbr 64258057Sbr#define GPIO_PDOR(n) (0x00 + 0x40 * (n >> 5)) 65258057Sbr#define GPIO_PSOR(n) (0x04 + 0x40 * (n >> 5)) 66258057Sbr#define GPIO_PCOR(n) (0x08 + 0x40 * (n >> 5)) 67258057Sbr#define GPIO_PTOR(n) (0x0C + 0x40 * (n >> 5)) 68258057Sbr#define GPIO_PDIR(n) (0x10 + 0x40 * (n >> 5)) 69258057Sbr 70258057Sbr#define GPIO_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) 71258057Sbr#define GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) 72258057Sbr 73258057Sbr#define DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT) 74258057Sbr 75258057Sbr/* 76258057Sbr * GPIO interface 77258057Sbr */ 78277996Sloosstatic device_t vf_gpio_get_bus(device_t); 79258057Sbrstatic int vf_gpio_pin_max(device_t, int *); 80258057Sbrstatic int vf_gpio_pin_getcaps(device_t, uint32_t, uint32_t *); 81258057Sbrstatic int vf_gpio_pin_getname(device_t, uint32_t, char *); 82258057Sbrstatic int vf_gpio_pin_getflags(device_t, uint32_t, uint32_t *); 83258057Sbrstatic int vf_gpio_pin_setflags(device_t, uint32_t, uint32_t); 84258057Sbrstatic int vf_gpio_pin_set(device_t, uint32_t, unsigned int); 85258057Sbrstatic int vf_gpio_pin_get(device_t, uint32_t, unsigned int *); 86258057Sbrstatic int vf_gpio_pin_toggle(device_t, uint32_t pin); 87258057Sbr 88258057Sbrstruct vf_gpio_softc { 89262885Sbr struct resource *res[1]; 90258057Sbr bus_space_tag_t bst; 91258057Sbr bus_space_handle_t bsh; 92258057Sbr 93277996Sloos device_t sc_busdev; 94258057Sbr struct mtx sc_mtx; 95258057Sbr int gpio_npins; 96258057Sbr struct gpio_pin gpio_pins[NGPIO]; 97258057Sbr}; 98258057Sbr 99258057Sbrstruct vf_gpio_softc *gpio_sc; 100258057Sbr 101258057Sbrstatic struct resource_spec vf_gpio_spec[] = { 102258057Sbr { SYS_RES_MEMORY, 0, RF_ACTIVE }, 103258057Sbr { -1, 0 } 104258057Sbr}; 105258057Sbr 106258057Sbrstatic int 107258057Sbrvf_gpio_probe(device_t dev) 108258057Sbr{ 109258057Sbr 110261410Sian if (!ofw_bus_status_okay(dev)) 111261410Sian return (ENXIO); 112261410Sian 113258057Sbr if (!ofw_bus_is_compatible(dev, "fsl,mvf600-gpio")) 114258057Sbr return (ENXIO); 115258057Sbr 116258057Sbr device_set_desc(dev, "Vybrid Family GPIO Unit"); 117258057Sbr return (BUS_PROBE_DEFAULT); 118258057Sbr} 119258057Sbr 120258057Sbrstatic int 121258057Sbrvf_gpio_attach(device_t dev) 122258057Sbr{ 123258057Sbr struct vf_gpio_softc *sc; 124262885Sbr int i; 125258057Sbr 126258057Sbr sc = device_get_softc(dev); 127258057Sbr mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 128258057Sbr 129258057Sbr if (bus_alloc_resources(dev, vf_gpio_spec, sc->res)) { 130258057Sbr device_printf(dev, "could not allocate resources\n"); 131277968Sloos mtx_destroy(&sc->sc_mtx); 132258057Sbr return (ENXIO); 133258057Sbr } 134258057Sbr 135258057Sbr /* Memory interface */ 136258057Sbr sc->bst = rman_get_bustag(sc->res[0]); 137258057Sbr sc->bsh = rman_get_bushandle(sc->res[0]); 138258057Sbr 139262885Sbr gpio_sc = sc; 140262885Sbr 141258057Sbr sc->gpio_npins = NGPIO; 142258057Sbr 143258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 144258057Sbr sc->gpio_pins[i].gp_pin = i; 145258057Sbr sc->gpio_pins[i].gp_caps = DEFAULT_CAPS; 146258057Sbr sc->gpio_pins[i].gp_flags = 147258057Sbr (READ4(sc, GPIO_PDOR(i)) & (1 << (i % 32))) ? 148258057Sbr GPIO_PIN_OUTPUT: GPIO_PIN_INPUT; 149258057Sbr snprintf(sc->gpio_pins[i].gp_name, GPIOMAXNAME, 150258057Sbr "vf_gpio%d.%d", device_get_unit(dev), i); 151258057Sbr } 152258057Sbr 153277996Sloos sc->sc_busdev = gpiobus_attach_bus(dev); 154277996Sloos if (sc->sc_busdev == NULL) { 155277996Sloos bus_release_resources(dev, vf_gpio_spec, sc->res); 156277996Sloos mtx_destroy(&sc->sc_mtx); 157277996Sloos return (ENXIO); 158277996Sloos } 159258057Sbr 160277996Sloos return (0); 161258057Sbr} 162258057Sbr 163277996Sloosstatic device_t 164277996Sloosvf_gpio_get_bus(device_t dev) 165277996Sloos{ 166277996Sloos struct vf_gpio_softc *sc; 167277996Sloos 168277996Sloos sc = device_get_softc(dev); 169277996Sloos 170277996Sloos return (sc->sc_busdev); 171277996Sloos} 172277996Sloos 173258057Sbrstatic int 174258057Sbrvf_gpio_pin_max(device_t dev, int *maxpin) 175258057Sbr{ 176258057Sbr 177258057Sbr *maxpin = NGPIO - 1; 178258057Sbr return (0); 179258057Sbr} 180258057Sbr 181258057Sbrstatic int 182258057Sbrvf_gpio_pin_getname(device_t dev, uint32_t pin, char *name) 183258057Sbr{ 184258057Sbr struct vf_gpio_softc *sc; 185258057Sbr int i; 186258057Sbr 187258057Sbr sc = device_get_softc(dev); 188258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 189258057Sbr if (sc->gpio_pins[i].gp_pin == pin) 190258057Sbr break; 191258057Sbr } 192258057Sbr 193258057Sbr if (i >= sc->gpio_npins) 194258057Sbr return (EINVAL); 195258057Sbr 196258057Sbr GPIO_LOCK(sc); 197258057Sbr memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME); 198258057Sbr GPIO_UNLOCK(sc); 199258057Sbr 200258057Sbr return (0); 201258057Sbr} 202258057Sbr 203258057Sbrstatic int 204258057Sbrvf_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) 205258057Sbr{ 206258057Sbr struct vf_gpio_softc *sc; 207258057Sbr int i; 208258057Sbr 209258057Sbr sc = device_get_softc(dev); 210258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 211258057Sbr if (sc->gpio_pins[i].gp_pin == pin) 212258057Sbr break; 213258057Sbr } 214258057Sbr 215258057Sbr if (i >= sc->gpio_npins) 216258057Sbr return (EINVAL); 217258057Sbr 218258057Sbr GPIO_LOCK(sc); 219258057Sbr *caps = sc->gpio_pins[i].gp_caps; 220258057Sbr GPIO_UNLOCK(sc); 221258057Sbr 222258057Sbr return (0); 223258057Sbr} 224258057Sbr 225258057Sbrstatic int 226258057Sbrvf_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) 227258057Sbr{ 228258057Sbr struct vf_gpio_softc *sc; 229258057Sbr int i; 230258057Sbr 231258057Sbr sc = device_get_softc(dev); 232258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 233258057Sbr if (sc->gpio_pins[i].gp_pin == pin) 234258057Sbr break; 235258057Sbr } 236258057Sbr 237258057Sbr if (i >= sc->gpio_npins) 238258057Sbr return (EINVAL); 239258057Sbr 240258057Sbr GPIO_LOCK(sc); 241258057Sbr *flags = sc->gpio_pins[i].gp_flags; 242258057Sbr GPIO_UNLOCK(sc); 243258057Sbr 244258057Sbr return (0); 245258057Sbr} 246258057Sbr 247258057Sbrstatic int 248258057Sbrvf_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) 249258057Sbr{ 250258057Sbr struct vf_gpio_softc *sc; 251258057Sbr int i; 252258057Sbr 253258057Sbr sc = device_get_softc(dev); 254258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 255258057Sbr if (sc->gpio_pins[i].gp_pin == pin) 256258057Sbr break; 257258057Sbr } 258258057Sbr 259258057Sbr if (i >= sc->gpio_npins) 260258057Sbr return (EINVAL); 261258057Sbr 262258057Sbr GPIO_LOCK(sc); 263266119Sbr *val = (READ4(sc, GPIO_PDIR(i)) & (1 << (i % 32))) ? 1 : 0; 264258057Sbr GPIO_UNLOCK(sc); 265258057Sbr 266258057Sbr return (0); 267258057Sbr} 268258057Sbr 269258057Sbrstatic int 270258057Sbrvf_gpio_pin_toggle(device_t dev, uint32_t pin) 271258057Sbr{ 272258057Sbr struct vf_gpio_softc *sc; 273258057Sbr int i; 274258057Sbr 275258057Sbr sc = device_get_softc(dev); 276258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 277258057Sbr if (sc->gpio_pins[i].gp_pin == pin) 278258057Sbr break; 279258057Sbr } 280258057Sbr 281258057Sbr if (i >= sc->gpio_npins) 282258057Sbr return (EINVAL); 283258057Sbr 284258057Sbr GPIO_LOCK(sc); 285258057Sbr WRITE4(sc, GPIO_PTOR(i), (1 << (i % 32))); 286258057Sbr GPIO_UNLOCK(sc); 287258057Sbr 288258057Sbr return (0); 289258057Sbr} 290258057Sbr 291258057Sbr 292258057Sbrstatic void 293258057Sbrvf_gpio_pin_configure(struct vf_gpio_softc *sc, struct gpio_pin *pin, 294258057Sbr unsigned int flags) 295258057Sbr{ 296258057Sbr 297258057Sbr GPIO_LOCK(sc); 298258057Sbr 299258057Sbr /* 300258057Sbr * Manage input/output 301258057Sbr */ 302258057Sbr if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) { 303258057Sbr pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT); 304258057Sbr if (flags & GPIO_PIN_OUTPUT) { 305258057Sbr pin->gp_flags |= GPIO_PIN_OUTPUT; 306258057Sbr 307258057Sbr } else { 308258057Sbr pin->gp_flags |= GPIO_PIN_INPUT; 309258057Sbr WRITE4(sc, GPIO_PCOR(pin->gp_pin), 310258057Sbr (1 << (pin->gp_pin % 32))); 311258057Sbr } 312258057Sbr } 313258057Sbr 314258057Sbr GPIO_UNLOCK(sc); 315258057Sbr} 316258057Sbr 317258057Sbr 318258057Sbrstatic int 319258057Sbrvf_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) 320258057Sbr{ 321258057Sbr struct vf_gpio_softc *sc; 322258057Sbr int i; 323258057Sbr 324258057Sbr sc = device_get_softc(dev); 325258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 326258057Sbr if (sc->gpio_pins[i].gp_pin == pin) 327258057Sbr break; 328258057Sbr } 329258057Sbr 330258057Sbr if (i >= sc->gpio_npins) 331258057Sbr return (EINVAL); 332258057Sbr 333258057Sbr vf_gpio_pin_configure(sc, &sc->gpio_pins[i], flags); 334258057Sbr 335258057Sbr return (0); 336258057Sbr} 337258057Sbr 338258057Sbrstatic int 339258057Sbrvf_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) 340258057Sbr{ 341258057Sbr struct vf_gpio_softc *sc; 342258057Sbr int i; 343258057Sbr 344258057Sbr sc = device_get_softc(dev); 345258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 346258057Sbr if (sc->gpio_pins[i].gp_pin == pin) 347258057Sbr break; 348258057Sbr } 349258057Sbr 350258057Sbr if (i >= sc->gpio_npins) 351258057Sbr return (EINVAL); 352258057Sbr 353258057Sbr GPIO_LOCK(sc); 354258057Sbr if (value) 355258057Sbr WRITE4(sc, GPIO_PSOR(i), (1 << (i % 32))); 356258057Sbr else 357258057Sbr WRITE4(sc, GPIO_PCOR(i), (1 << (i % 32))); 358258057Sbr GPIO_UNLOCK(sc); 359258057Sbr 360258057Sbr return (0); 361258057Sbr} 362258057Sbr 363258057Sbrstatic device_method_t vf_gpio_methods[] = { 364258057Sbr DEVMETHOD(device_probe, vf_gpio_probe), 365258057Sbr DEVMETHOD(device_attach, vf_gpio_attach), 366258057Sbr 367258057Sbr /* GPIO protocol */ 368277996Sloos DEVMETHOD(gpio_get_bus, vf_gpio_get_bus), 369258057Sbr DEVMETHOD(gpio_pin_max, vf_gpio_pin_max), 370258057Sbr DEVMETHOD(gpio_pin_getname, vf_gpio_pin_getname), 371258057Sbr DEVMETHOD(gpio_pin_getcaps, vf_gpio_pin_getcaps), 372258057Sbr DEVMETHOD(gpio_pin_getflags, vf_gpio_pin_getflags), 373258057Sbr DEVMETHOD(gpio_pin_get, vf_gpio_pin_get), 374258057Sbr DEVMETHOD(gpio_pin_toggle, vf_gpio_pin_toggle), 375258057Sbr DEVMETHOD(gpio_pin_setflags, vf_gpio_pin_setflags), 376258057Sbr DEVMETHOD(gpio_pin_set, vf_gpio_pin_set), 377258057Sbr { 0, 0 } 378258057Sbr}; 379258057Sbr 380258057Sbrstatic driver_t vf_gpio_driver = { 381258057Sbr "gpio", 382258057Sbr vf_gpio_methods, 383258057Sbr sizeof(struct vf_gpio_softc), 384258057Sbr}; 385258057Sbr 386258057Sbrstatic devclass_t vf_gpio_devclass; 387258057Sbr 388258057SbrDRIVER_MODULE(vf_gpio, simplebus, vf_gpio_driver, vf_gpio_devclass, 0, 0); 389