vf_gpio.c revision 266119
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 266119 2014-05-15 10:06:59Z br $"); 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"); 128258057Sbr return (ENXIO); 129258057Sbr } 130258057Sbr 131258057Sbr /* Memory interface */ 132258057Sbr sc->bst = rman_get_bustag(sc->res[0]); 133258057Sbr sc->bsh = rman_get_bushandle(sc->res[0]); 134258057Sbr 135262885Sbr gpio_sc = sc; 136262885Sbr 137258057Sbr sc->gpio_npins = NGPIO; 138258057Sbr 139258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 140258057Sbr sc->gpio_pins[i].gp_pin = i; 141258057Sbr sc->gpio_pins[i].gp_caps = DEFAULT_CAPS; 142258057Sbr sc->gpio_pins[i].gp_flags = 143258057Sbr (READ4(sc, GPIO_PDOR(i)) & (1 << (i % 32))) ? 144258057Sbr GPIO_PIN_OUTPUT: GPIO_PIN_INPUT; 145258057Sbr snprintf(sc->gpio_pins[i].gp_name, GPIOMAXNAME, 146258057Sbr "vf_gpio%d.%d", device_get_unit(dev), i); 147258057Sbr } 148258057Sbr 149258057Sbr device_add_child(dev, "gpioc", device_get_unit(dev)); 150258057Sbr device_add_child(dev, "gpiobus", device_get_unit(dev)); 151258057Sbr 152258057Sbr return (bus_generic_attach(dev)); 153258057Sbr} 154258057Sbr 155258057Sbrstatic int 156258057Sbrvf_gpio_pin_max(device_t dev, int *maxpin) 157258057Sbr{ 158258057Sbr 159258057Sbr *maxpin = NGPIO - 1; 160258057Sbr return (0); 161258057Sbr} 162258057Sbr 163258057Sbrstatic int 164258057Sbrvf_gpio_pin_getname(device_t dev, uint32_t pin, char *name) 165258057Sbr{ 166258057Sbr struct vf_gpio_softc *sc; 167258057Sbr int i; 168258057Sbr 169258057Sbr sc = device_get_softc(dev); 170258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 171258057Sbr if (sc->gpio_pins[i].gp_pin == pin) 172258057Sbr break; 173258057Sbr } 174258057Sbr 175258057Sbr if (i >= sc->gpio_npins) 176258057Sbr return (EINVAL); 177258057Sbr 178258057Sbr GPIO_LOCK(sc); 179258057Sbr memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME); 180258057Sbr GPIO_UNLOCK(sc); 181258057Sbr 182258057Sbr return (0); 183258057Sbr} 184258057Sbr 185258057Sbrstatic int 186258057Sbrvf_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) 187258057Sbr{ 188258057Sbr struct vf_gpio_softc *sc; 189258057Sbr int i; 190258057Sbr 191258057Sbr sc = device_get_softc(dev); 192258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 193258057Sbr if (sc->gpio_pins[i].gp_pin == pin) 194258057Sbr break; 195258057Sbr } 196258057Sbr 197258057Sbr if (i >= sc->gpio_npins) 198258057Sbr return (EINVAL); 199258057Sbr 200258057Sbr GPIO_LOCK(sc); 201258057Sbr *caps = sc->gpio_pins[i].gp_caps; 202258057Sbr GPIO_UNLOCK(sc); 203258057Sbr 204258057Sbr return (0); 205258057Sbr} 206258057Sbr 207258057Sbrstatic int 208258057Sbrvf_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) 209258057Sbr{ 210258057Sbr struct vf_gpio_softc *sc; 211258057Sbr int i; 212258057Sbr 213258057Sbr sc = device_get_softc(dev); 214258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 215258057Sbr if (sc->gpio_pins[i].gp_pin == pin) 216258057Sbr break; 217258057Sbr } 218258057Sbr 219258057Sbr if (i >= sc->gpio_npins) 220258057Sbr return (EINVAL); 221258057Sbr 222258057Sbr GPIO_LOCK(sc); 223258057Sbr *flags = sc->gpio_pins[i].gp_flags; 224258057Sbr GPIO_UNLOCK(sc); 225258057Sbr 226258057Sbr return (0); 227258057Sbr} 228258057Sbr 229258057Sbrstatic int 230258057Sbrvf_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) 231258057Sbr{ 232258057Sbr struct vf_gpio_softc *sc; 233258057Sbr int i; 234258057Sbr 235258057Sbr sc = device_get_softc(dev); 236258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 237258057Sbr if (sc->gpio_pins[i].gp_pin == pin) 238258057Sbr break; 239258057Sbr } 240258057Sbr 241258057Sbr if (i >= sc->gpio_npins) 242258057Sbr return (EINVAL); 243258057Sbr 244258057Sbr GPIO_LOCK(sc); 245266119Sbr *val = (READ4(sc, GPIO_PDIR(i)) & (1 << (i % 32))) ? 1 : 0; 246258057Sbr GPIO_UNLOCK(sc); 247258057Sbr 248258057Sbr return (0); 249258057Sbr} 250258057Sbr 251258057Sbrstatic int 252258057Sbrvf_gpio_pin_toggle(device_t dev, uint32_t pin) 253258057Sbr{ 254258057Sbr struct vf_gpio_softc *sc; 255258057Sbr int i; 256258057Sbr 257258057Sbr sc = device_get_softc(dev); 258258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 259258057Sbr if (sc->gpio_pins[i].gp_pin == pin) 260258057Sbr break; 261258057Sbr } 262258057Sbr 263258057Sbr if (i >= sc->gpio_npins) 264258057Sbr return (EINVAL); 265258057Sbr 266258057Sbr GPIO_LOCK(sc); 267258057Sbr WRITE4(sc, GPIO_PTOR(i), (1 << (i % 32))); 268258057Sbr GPIO_UNLOCK(sc); 269258057Sbr 270258057Sbr return (0); 271258057Sbr} 272258057Sbr 273258057Sbr 274258057Sbrstatic void 275258057Sbrvf_gpio_pin_configure(struct vf_gpio_softc *sc, struct gpio_pin *pin, 276258057Sbr unsigned int flags) 277258057Sbr{ 278258057Sbr 279258057Sbr GPIO_LOCK(sc); 280258057Sbr 281258057Sbr /* 282258057Sbr * Manage input/output 283258057Sbr */ 284258057Sbr if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) { 285258057Sbr pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT); 286258057Sbr if (flags & GPIO_PIN_OUTPUT) { 287258057Sbr pin->gp_flags |= GPIO_PIN_OUTPUT; 288258057Sbr 289258057Sbr } else { 290258057Sbr pin->gp_flags |= GPIO_PIN_INPUT; 291258057Sbr WRITE4(sc, GPIO_PCOR(pin->gp_pin), 292258057Sbr (1 << (pin->gp_pin % 32))); 293258057Sbr } 294258057Sbr } 295258057Sbr 296258057Sbr GPIO_UNLOCK(sc); 297258057Sbr} 298258057Sbr 299258057Sbr 300258057Sbrstatic int 301258057Sbrvf_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) 302258057Sbr{ 303258057Sbr struct vf_gpio_softc *sc; 304258057Sbr int i; 305258057Sbr 306258057Sbr sc = device_get_softc(dev); 307258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 308258057Sbr if (sc->gpio_pins[i].gp_pin == pin) 309258057Sbr break; 310258057Sbr } 311258057Sbr 312258057Sbr if (i >= sc->gpio_npins) 313258057Sbr return (EINVAL); 314258057Sbr 315258057Sbr /* Check for unwanted flags. */ 316258057Sbr if ((flags & sc->gpio_pins[i].gp_caps) != flags) 317258057Sbr return (EINVAL); 318258057Sbr 319258057Sbr /* Can't mix input/output together */ 320258057Sbr if ((flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) == 321258057Sbr (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) 322258057Sbr return (EINVAL); 323258057Sbr 324258057Sbr vf_gpio_pin_configure(sc, &sc->gpio_pins[i], flags); 325258057Sbr 326258057Sbr return (0); 327258057Sbr} 328258057Sbr 329258057Sbrstatic int 330258057Sbrvf_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) 331258057Sbr{ 332258057Sbr struct vf_gpio_softc *sc; 333258057Sbr int i; 334258057Sbr 335258057Sbr sc = device_get_softc(dev); 336258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 337258057Sbr if (sc->gpio_pins[i].gp_pin == pin) 338258057Sbr break; 339258057Sbr } 340258057Sbr 341258057Sbr if (i >= sc->gpio_npins) 342258057Sbr return (EINVAL); 343258057Sbr 344258057Sbr GPIO_LOCK(sc); 345258057Sbr if (value) 346258057Sbr WRITE4(sc, GPIO_PSOR(i), (1 << (i % 32))); 347258057Sbr else 348258057Sbr WRITE4(sc, GPIO_PCOR(i), (1 << (i % 32))); 349258057Sbr GPIO_UNLOCK(sc); 350258057Sbr 351258057Sbr return (0); 352258057Sbr} 353258057Sbr 354258057Sbrstatic device_method_t vf_gpio_methods[] = { 355258057Sbr DEVMETHOD(device_probe, vf_gpio_probe), 356258057Sbr DEVMETHOD(device_attach, vf_gpio_attach), 357258057Sbr 358258057Sbr /* GPIO protocol */ 359258057Sbr DEVMETHOD(gpio_pin_max, vf_gpio_pin_max), 360258057Sbr DEVMETHOD(gpio_pin_getname, vf_gpio_pin_getname), 361258057Sbr DEVMETHOD(gpio_pin_getcaps, vf_gpio_pin_getcaps), 362258057Sbr DEVMETHOD(gpio_pin_getflags, vf_gpio_pin_getflags), 363258057Sbr DEVMETHOD(gpio_pin_get, vf_gpio_pin_get), 364258057Sbr DEVMETHOD(gpio_pin_toggle, vf_gpio_pin_toggle), 365258057Sbr DEVMETHOD(gpio_pin_setflags, vf_gpio_pin_setflags), 366258057Sbr DEVMETHOD(gpio_pin_set, vf_gpio_pin_set), 367258057Sbr { 0, 0 } 368258057Sbr}; 369258057Sbr 370258057Sbrstatic driver_t vf_gpio_driver = { 371258057Sbr "gpio", 372258057Sbr vf_gpio_methods, 373258057Sbr sizeof(struct vf_gpio_softc), 374258057Sbr}; 375258057Sbr 376258057Sbrstatic devclass_t vf_gpio_devclass; 377258057Sbr 378258057SbrDRIVER_MODULE(vf_gpio, simplebus, vf_gpio_driver, vf_gpio_devclass, 0, 0); 379