vf_gpio.c revision 277968
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 277968 2015-01-31 12:17:07Z 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> 49258057Sbr#include <dev/ofw/openfirm.h> 50258057Sbr#include <dev/ofw/ofw_bus.h> 51258057Sbr#include <dev/ofw/ofw_bus_subr.h> 52258057Sbr 53258057Sbr#include <machine/bus.h> 54258057Sbr#include <machine/fdt.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 */ 77258057Sbrstatic int vf_gpio_pin_max(device_t, int *); 78258057Sbrstatic int vf_gpio_pin_getcaps(device_t, uint32_t, uint32_t *); 79258057Sbrstatic int vf_gpio_pin_getname(device_t, uint32_t, char *); 80258057Sbrstatic int vf_gpio_pin_getflags(device_t, uint32_t, uint32_t *); 81258057Sbrstatic int vf_gpio_pin_setflags(device_t, uint32_t, uint32_t); 82258057Sbrstatic int vf_gpio_pin_set(device_t, uint32_t, unsigned int); 83258057Sbrstatic int vf_gpio_pin_get(device_t, uint32_t, unsigned int *); 84258057Sbrstatic int vf_gpio_pin_toggle(device_t, uint32_t pin); 85258057Sbr 86258057Sbrstruct vf_gpio_softc { 87262885Sbr struct resource *res[1]; 88258057Sbr bus_space_tag_t bst; 89258057Sbr bus_space_handle_t bsh; 90258057Sbr 91258057Sbr struct mtx sc_mtx; 92258057Sbr int gpio_npins; 93258057Sbr struct gpio_pin gpio_pins[NGPIO]; 94258057Sbr}; 95258057Sbr 96258057Sbrstruct vf_gpio_softc *gpio_sc; 97258057Sbr 98258057Sbrstatic struct resource_spec vf_gpio_spec[] = { 99258057Sbr { SYS_RES_MEMORY, 0, RF_ACTIVE }, 100258057Sbr { -1, 0 } 101258057Sbr}; 102258057Sbr 103258057Sbrstatic int 104258057Sbrvf_gpio_probe(device_t dev) 105258057Sbr{ 106258057Sbr 107261410Sian if (!ofw_bus_status_okay(dev)) 108261410Sian return (ENXIO); 109261410Sian 110258057Sbr if (!ofw_bus_is_compatible(dev, "fsl,mvf600-gpio")) 111258057Sbr return (ENXIO); 112258057Sbr 113258057Sbr device_set_desc(dev, "Vybrid Family GPIO Unit"); 114258057Sbr return (BUS_PROBE_DEFAULT); 115258057Sbr} 116258057Sbr 117258057Sbrstatic int 118258057Sbrvf_gpio_attach(device_t dev) 119258057Sbr{ 120258057Sbr struct vf_gpio_softc *sc; 121262885Sbr int i; 122258057Sbr 123258057Sbr sc = device_get_softc(dev); 124258057Sbr mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 125258057Sbr 126258057Sbr if (bus_alloc_resources(dev, vf_gpio_spec, sc->res)) { 127258057Sbr device_printf(dev, "could not allocate resources\n"); 128277968Sloos mtx_destroy(&sc->sc_mtx); 129258057Sbr return (ENXIO); 130258057Sbr } 131258057Sbr 132258057Sbr /* Memory interface */ 133258057Sbr sc->bst = rman_get_bustag(sc->res[0]); 134258057Sbr sc->bsh = rman_get_bushandle(sc->res[0]); 135258057Sbr 136262885Sbr gpio_sc = sc; 137262885Sbr 138258057Sbr sc->gpio_npins = NGPIO; 139258057Sbr 140258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 141258057Sbr sc->gpio_pins[i].gp_pin = i; 142258057Sbr sc->gpio_pins[i].gp_caps = DEFAULT_CAPS; 143258057Sbr sc->gpio_pins[i].gp_flags = 144258057Sbr (READ4(sc, GPIO_PDOR(i)) & (1 << (i % 32))) ? 145258057Sbr GPIO_PIN_OUTPUT: GPIO_PIN_INPUT; 146258057Sbr snprintf(sc->gpio_pins[i].gp_name, GPIOMAXNAME, 147258057Sbr "vf_gpio%d.%d", device_get_unit(dev), i); 148258057Sbr } 149258057Sbr 150273799Sloos device_add_child(dev, "gpioc", -1); 151273799Sloos device_add_child(dev, "gpiobus", -1); 152258057Sbr 153258057Sbr return (bus_generic_attach(dev)); 154258057Sbr} 155258057Sbr 156258057Sbrstatic int 157258057Sbrvf_gpio_pin_max(device_t dev, int *maxpin) 158258057Sbr{ 159258057Sbr 160258057Sbr *maxpin = NGPIO - 1; 161258057Sbr return (0); 162258057Sbr} 163258057Sbr 164258057Sbrstatic int 165258057Sbrvf_gpio_pin_getname(device_t dev, uint32_t pin, char *name) 166258057Sbr{ 167258057Sbr struct vf_gpio_softc *sc; 168258057Sbr int i; 169258057Sbr 170258057Sbr sc = device_get_softc(dev); 171258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 172258057Sbr if (sc->gpio_pins[i].gp_pin == pin) 173258057Sbr break; 174258057Sbr } 175258057Sbr 176258057Sbr if (i >= sc->gpio_npins) 177258057Sbr return (EINVAL); 178258057Sbr 179258057Sbr GPIO_LOCK(sc); 180258057Sbr memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME); 181258057Sbr GPIO_UNLOCK(sc); 182258057Sbr 183258057Sbr return (0); 184258057Sbr} 185258057Sbr 186258057Sbrstatic int 187258057Sbrvf_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) 188258057Sbr{ 189258057Sbr struct vf_gpio_softc *sc; 190258057Sbr int i; 191258057Sbr 192258057Sbr sc = device_get_softc(dev); 193258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 194258057Sbr if (sc->gpio_pins[i].gp_pin == pin) 195258057Sbr break; 196258057Sbr } 197258057Sbr 198258057Sbr if (i >= sc->gpio_npins) 199258057Sbr return (EINVAL); 200258057Sbr 201258057Sbr GPIO_LOCK(sc); 202258057Sbr *caps = sc->gpio_pins[i].gp_caps; 203258057Sbr GPIO_UNLOCK(sc); 204258057Sbr 205258057Sbr return (0); 206258057Sbr} 207258057Sbr 208258057Sbrstatic int 209258057Sbrvf_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) 210258057Sbr{ 211258057Sbr struct vf_gpio_softc *sc; 212258057Sbr int i; 213258057Sbr 214258057Sbr sc = device_get_softc(dev); 215258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 216258057Sbr if (sc->gpio_pins[i].gp_pin == pin) 217258057Sbr break; 218258057Sbr } 219258057Sbr 220258057Sbr if (i >= sc->gpio_npins) 221258057Sbr return (EINVAL); 222258057Sbr 223258057Sbr GPIO_LOCK(sc); 224258057Sbr *flags = sc->gpio_pins[i].gp_flags; 225258057Sbr GPIO_UNLOCK(sc); 226258057Sbr 227258057Sbr return (0); 228258057Sbr} 229258057Sbr 230258057Sbrstatic int 231258057Sbrvf_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) 232258057Sbr{ 233258057Sbr struct vf_gpio_softc *sc; 234258057Sbr int i; 235258057Sbr 236258057Sbr sc = device_get_softc(dev); 237258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 238258057Sbr if (sc->gpio_pins[i].gp_pin == pin) 239258057Sbr break; 240258057Sbr } 241258057Sbr 242258057Sbr if (i >= sc->gpio_npins) 243258057Sbr return (EINVAL); 244258057Sbr 245258057Sbr GPIO_LOCK(sc); 246266119Sbr *val = (READ4(sc, GPIO_PDIR(i)) & (1 << (i % 32))) ? 1 : 0; 247258057Sbr GPIO_UNLOCK(sc); 248258057Sbr 249258057Sbr return (0); 250258057Sbr} 251258057Sbr 252258057Sbrstatic int 253258057Sbrvf_gpio_pin_toggle(device_t dev, uint32_t pin) 254258057Sbr{ 255258057Sbr struct vf_gpio_softc *sc; 256258057Sbr int i; 257258057Sbr 258258057Sbr sc = device_get_softc(dev); 259258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 260258057Sbr if (sc->gpio_pins[i].gp_pin == pin) 261258057Sbr break; 262258057Sbr } 263258057Sbr 264258057Sbr if (i >= sc->gpio_npins) 265258057Sbr return (EINVAL); 266258057Sbr 267258057Sbr GPIO_LOCK(sc); 268258057Sbr WRITE4(sc, GPIO_PTOR(i), (1 << (i % 32))); 269258057Sbr GPIO_UNLOCK(sc); 270258057Sbr 271258057Sbr return (0); 272258057Sbr} 273258057Sbr 274258057Sbr 275258057Sbrstatic void 276258057Sbrvf_gpio_pin_configure(struct vf_gpio_softc *sc, struct gpio_pin *pin, 277258057Sbr unsigned int flags) 278258057Sbr{ 279258057Sbr 280258057Sbr GPIO_LOCK(sc); 281258057Sbr 282258057Sbr /* 283258057Sbr * Manage input/output 284258057Sbr */ 285258057Sbr if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) { 286258057Sbr pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT); 287258057Sbr if (flags & GPIO_PIN_OUTPUT) { 288258057Sbr pin->gp_flags |= GPIO_PIN_OUTPUT; 289258057Sbr 290258057Sbr } else { 291258057Sbr pin->gp_flags |= GPIO_PIN_INPUT; 292258057Sbr WRITE4(sc, GPIO_PCOR(pin->gp_pin), 293258057Sbr (1 << (pin->gp_pin % 32))); 294258057Sbr } 295258057Sbr } 296258057Sbr 297258057Sbr GPIO_UNLOCK(sc); 298258057Sbr} 299258057Sbr 300258057Sbr 301258057Sbrstatic int 302258057Sbrvf_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) 303258057Sbr{ 304258057Sbr struct vf_gpio_softc *sc; 305258057Sbr int i; 306258057Sbr 307258057Sbr sc = device_get_softc(dev); 308258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 309258057Sbr if (sc->gpio_pins[i].gp_pin == pin) 310258057Sbr break; 311258057Sbr } 312258057Sbr 313258057Sbr if (i >= sc->gpio_npins) 314258057Sbr return (EINVAL); 315258057Sbr 316258057Sbr vf_gpio_pin_configure(sc, &sc->gpio_pins[i], flags); 317258057Sbr 318258057Sbr return (0); 319258057Sbr} 320258057Sbr 321258057Sbrstatic int 322258057Sbrvf_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) 323258057Sbr{ 324258057Sbr struct vf_gpio_softc *sc; 325258057Sbr int i; 326258057Sbr 327258057Sbr sc = device_get_softc(dev); 328258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 329258057Sbr if (sc->gpio_pins[i].gp_pin == pin) 330258057Sbr break; 331258057Sbr } 332258057Sbr 333258057Sbr if (i >= sc->gpio_npins) 334258057Sbr return (EINVAL); 335258057Sbr 336258057Sbr GPIO_LOCK(sc); 337258057Sbr if (value) 338258057Sbr WRITE4(sc, GPIO_PSOR(i), (1 << (i % 32))); 339258057Sbr else 340258057Sbr WRITE4(sc, GPIO_PCOR(i), (1 << (i % 32))); 341258057Sbr GPIO_UNLOCK(sc); 342258057Sbr 343258057Sbr return (0); 344258057Sbr} 345258057Sbr 346258057Sbrstatic device_method_t vf_gpio_methods[] = { 347258057Sbr DEVMETHOD(device_probe, vf_gpio_probe), 348258057Sbr DEVMETHOD(device_attach, vf_gpio_attach), 349258057Sbr 350258057Sbr /* GPIO protocol */ 351258057Sbr DEVMETHOD(gpio_pin_max, vf_gpio_pin_max), 352258057Sbr DEVMETHOD(gpio_pin_getname, vf_gpio_pin_getname), 353258057Sbr DEVMETHOD(gpio_pin_getcaps, vf_gpio_pin_getcaps), 354258057Sbr DEVMETHOD(gpio_pin_getflags, vf_gpio_pin_getflags), 355258057Sbr DEVMETHOD(gpio_pin_get, vf_gpio_pin_get), 356258057Sbr DEVMETHOD(gpio_pin_toggle, vf_gpio_pin_toggle), 357258057Sbr DEVMETHOD(gpio_pin_setflags, vf_gpio_pin_setflags), 358258057Sbr DEVMETHOD(gpio_pin_set, vf_gpio_pin_set), 359258057Sbr { 0, 0 } 360258057Sbr}; 361258057Sbr 362258057Sbrstatic driver_t vf_gpio_driver = { 363258057Sbr "gpio", 364258057Sbr vf_gpio_methods, 365258057Sbr sizeof(struct vf_gpio_softc), 366258057Sbr}; 367258057Sbr 368258057Sbrstatic devclass_t vf_gpio_devclass; 369258057Sbr 370258057SbrDRIVER_MODULE(vf_gpio, simplebus, vf_gpio_driver, vf_gpio_devclass, 0, 0); 371