vf_gpio.c revision 261410
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 261410 2014-02-02 19:17:28Z ian $"); 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> 61258057Sbr 62258057Sbr#define GPIO_PDOR(n) (0x00 + 0x40 * (n >> 5)) 63258057Sbr#define GPIO_PSOR(n) (0x04 + 0x40 * (n >> 5)) 64258057Sbr#define GPIO_PCOR(n) (0x08 + 0x40 * (n >> 5)) 65258057Sbr#define GPIO_PTOR(n) (0x0C + 0x40 * (n >> 5)) 66258057Sbr#define GPIO_PDIR(n) (0x10 + 0x40 * (n >> 5)) 67258057Sbr 68258057Sbr#define GPIO_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) 69258057Sbr#define GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) 70258057Sbr 71258057Sbr#define NPORTS 5 72258057Sbr#define NGPIO (NPORTS * 32) 73258057Sbr#define DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT) 74258057Sbr 75258057Sbr/* 76258057Sbr * GPIO interface 77258057Sbr */ 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 { 88258057Sbr struct resource *res[6]; 89258057Sbr bus_space_tag_t bst; 90258057Sbr bus_space_handle_t bsh; 91258057Sbr 92258057Sbr struct mtx sc_mtx; 93258057Sbr int gpio_npins; 94258057Sbr struct gpio_pin gpio_pins[NGPIO]; 95258057Sbr void *gpio_ih[NPORTS]; 96258057Sbr}; 97258057Sbr 98258057Sbrstruct vf_gpio_softc *gpio_sc; 99258057Sbr 100258057Sbrstatic struct resource_spec vf_gpio_spec[] = { 101258057Sbr { SYS_RES_MEMORY, 0, RF_ACTIVE }, 102258057Sbr { SYS_RES_IRQ, 0, RF_ACTIVE }, 103258057Sbr { SYS_RES_IRQ, 1, RF_ACTIVE }, 104258057Sbr { SYS_RES_IRQ, 2, RF_ACTIVE }, 105258057Sbr { SYS_RES_IRQ, 3, RF_ACTIVE }, 106258057Sbr { SYS_RES_IRQ, 4, RF_ACTIVE }, 107258057Sbr { -1, 0 } 108258057Sbr}; 109258057Sbr 110258057Sbrstatic int 111258057Sbrvf_gpio_intr(void *arg) 112258057Sbr{ 113258057Sbr struct vf_gpio_softc *sc; 114258057Sbr sc = arg; 115258057Sbr 116258057Sbr /* TODO: interrupt handling */ 117258057Sbr 118258057Sbr return (FILTER_HANDLED); 119258057Sbr} 120258057Sbr 121258057Sbr 122258057Sbrstatic int 123258057Sbrvf_gpio_probe(device_t dev) 124258057Sbr{ 125258057Sbr 126261410Sian if (!ofw_bus_status_okay(dev)) 127261410Sian return (ENXIO); 128261410Sian 129258057Sbr if (!ofw_bus_is_compatible(dev, "fsl,mvf600-gpio")) 130258057Sbr return (ENXIO); 131258057Sbr 132258057Sbr device_set_desc(dev, "Vybrid Family GPIO Unit"); 133258057Sbr return (BUS_PROBE_DEFAULT); 134258057Sbr} 135258057Sbr 136258057Sbrstatic int 137258057Sbrvf_gpio_attach(device_t dev) 138258057Sbr{ 139258057Sbr struct vf_gpio_softc *sc; 140258057Sbr int irq, i; 141258057Sbr 142258057Sbr sc = device_get_softc(dev); 143258057Sbr mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 144258057Sbr 145258057Sbr if (bus_alloc_resources(dev, vf_gpio_spec, sc->res)) { 146258057Sbr device_printf(dev, "could not allocate resources\n"); 147258057Sbr return (ENXIO); 148258057Sbr } 149258057Sbr 150258057Sbr gpio_sc = sc; 151258057Sbr 152258057Sbr /* Memory interface */ 153258057Sbr sc->bst = rman_get_bustag(sc->res[0]); 154258057Sbr sc->bsh = rman_get_bushandle(sc->res[0]); 155258057Sbr 156258057Sbr sc->gpio_npins = NGPIO; 157258057Sbr 158258057Sbr for (irq = 0; irq < NPORTS; irq ++) { 159258057Sbr if ((bus_setup_intr(dev, sc->res[1 + irq], INTR_TYPE_MISC, 160258057Sbr vf_gpio_intr, NULL, sc, &sc->gpio_ih[irq]))) { 161258057Sbr device_printf(dev, 162258057Sbr "WARNING: unable to register interrupt handler\n"); 163258057Sbr return (ENXIO); 164258057Sbr } 165258057Sbr } 166258057Sbr 167258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 168258057Sbr sc->gpio_pins[i].gp_pin = i; 169258057Sbr sc->gpio_pins[i].gp_caps = DEFAULT_CAPS; 170258057Sbr sc->gpio_pins[i].gp_flags = 171258057Sbr (READ4(sc, GPIO_PDOR(i)) & (1 << (i % 32))) ? 172258057Sbr GPIO_PIN_OUTPUT: GPIO_PIN_INPUT; 173258057Sbr snprintf(sc->gpio_pins[i].gp_name, GPIOMAXNAME, 174258057Sbr "vf_gpio%d.%d", device_get_unit(dev), i); 175258057Sbr } 176258057Sbr 177258057Sbr device_add_child(dev, "gpioc", device_get_unit(dev)); 178258057Sbr device_add_child(dev, "gpiobus", device_get_unit(dev)); 179258057Sbr 180258057Sbr return (bus_generic_attach(dev)); 181258057Sbr} 182258057Sbr 183258057Sbrstatic int 184258057Sbrvf_gpio_pin_max(device_t dev, int *maxpin) 185258057Sbr{ 186258057Sbr 187258057Sbr *maxpin = NGPIO - 1; 188258057Sbr return (0); 189258057Sbr} 190258057Sbr 191258057Sbrstatic int 192258057Sbrvf_gpio_pin_getname(device_t dev, uint32_t pin, char *name) 193258057Sbr{ 194258057Sbr struct vf_gpio_softc *sc; 195258057Sbr int i; 196258057Sbr 197258057Sbr sc = device_get_softc(dev); 198258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 199258057Sbr if (sc->gpio_pins[i].gp_pin == pin) 200258057Sbr break; 201258057Sbr } 202258057Sbr 203258057Sbr if (i >= sc->gpio_npins) 204258057Sbr return (EINVAL); 205258057Sbr 206258057Sbr GPIO_LOCK(sc); 207258057Sbr memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME); 208258057Sbr GPIO_UNLOCK(sc); 209258057Sbr 210258057Sbr return (0); 211258057Sbr} 212258057Sbr 213258057Sbrstatic int 214258057Sbrvf_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) 215258057Sbr{ 216258057Sbr struct vf_gpio_softc *sc; 217258057Sbr int i; 218258057Sbr 219258057Sbr sc = device_get_softc(dev); 220258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 221258057Sbr if (sc->gpio_pins[i].gp_pin == pin) 222258057Sbr break; 223258057Sbr } 224258057Sbr 225258057Sbr if (i >= sc->gpio_npins) 226258057Sbr return (EINVAL); 227258057Sbr 228258057Sbr GPIO_LOCK(sc); 229258057Sbr *caps = sc->gpio_pins[i].gp_caps; 230258057Sbr GPIO_UNLOCK(sc); 231258057Sbr 232258057Sbr return (0); 233258057Sbr} 234258057Sbr 235258057Sbrstatic int 236258057Sbrvf_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) 237258057Sbr{ 238258057Sbr struct vf_gpio_softc *sc; 239258057Sbr int i; 240258057Sbr 241258057Sbr sc = device_get_softc(dev); 242258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 243258057Sbr if (sc->gpio_pins[i].gp_pin == pin) 244258057Sbr break; 245258057Sbr } 246258057Sbr 247258057Sbr if (i >= sc->gpio_npins) 248258057Sbr return (EINVAL); 249258057Sbr 250258057Sbr GPIO_LOCK(sc); 251258057Sbr *flags = sc->gpio_pins[i].gp_flags; 252258057Sbr GPIO_UNLOCK(sc); 253258057Sbr 254258057Sbr return (0); 255258057Sbr} 256258057Sbr 257258057Sbrstatic int 258258057Sbrvf_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) 259258057Sbr{ 260258057Sbr struct vf_gpio_softc *sc; 261258057Sbr int i; 262258057Sbr 263258057Sbr sc = device_get_softc(dev); 264258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 265258057Sbr if (sc->gpio_pins[i].gp_pin == pin) 266258057Sbr break; 267258057Sbr } 268258057Sbr 269258057Sbr if (i >= sc->gpio_npins) 270258057Sbr return (EINVAL); 271258057Sbr 272258057Sbr GPIO_LOCK(sc); 273258057Sbr *val = (READ4(sc, GPIO_PDOR(i)) & (1 << (i % 32))); 274258057Sbr GPIO_UNLOCK(sc); 275258057Sbr 276258057Sbr return (0); 277258057Sbr} 278258057Sbr 279258057Sbrstatic int 280258057Sbrvf_gpio_pin_toggle(device_t dev, uint32_t pin) 281258057Sbr{ 282258057Sbr struct vf_gpio_softc *sc; 283258057Sbr int i; 284258057Sbr 285258057Sbr sc = device_get_softc(dev); 286258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 287258057Sbr if (sc->gpio_pins[i].gp_pin == pin) 288258057Sbr break; 289258057Sbr } 290258057Sbr 291258057Sbr if (i >= sc->gpio_npins) 292258057Sbr return (EINVAL); 293258057Sbr 294258057Sbr GPIO_LOCK(sc); 295258057Sbr WRITE4(sc, GPIO_PTOR(i), (1 << (i % 32))); 296258057Sbr GPIO_UNLOCK(sc); 297258057Sbr 298258057Sbr return (0); 299258057Sbr} 300258057Sbr 301258057Sbr 302258057Sbrstatic void 303258057Sbrvf_gpio_pin_configure(struct vf_gpio_softc *sc, struct gpio_pin *pin, 304258057Sbr unsigned int flags) 305258057Sbr{ 306258057Sbr 307258057Sbr GPIO_LOCK(sc); 308258057Sbr 309258057Sbr /* 310258057Sbr * Manage input/output 311258057Sbr */ 312258057Sbr if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) { 313258057Sbr pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT); 314258057Sbr if (flags & GPIO_PIN_OUTPUT) { 315258057Sbr pin->gp_flags |= GPIO_PIN_OUTPUT; 316258057Sbr 317258057Sbr } else { 318258057Sbr pin->gp_flags |= GPIO_PIN_INPUT; 319258057Sbr WRITE4(sc, GPIO_PCOR(pin->gp_pin), 320258057Sbr (1 << (pin->gp_pin % 32))); 321258057Sbr } 322258057Sbr } 323258057Sbr 324258057Sbr GPIO_UNLOCK(sc); 325258057Sbr} 326258057Sbr 327258057Sbr 328258057Sbrstatic int 329258057Sbrvf_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) 330258057Sbr{ 331258057Sbr struct vf_gpio_softc *sc; 332258057Sbr int i; 333258057Sbr 334258057Sbr sc = device_get_softc(dev); 335258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 336258057Sbr if (sc->gpio_pins[i].gp_pin == pin) 337258057Sbr break; 338258057Sbr } 339258057Sbr 340258057Sbr if (i >= sc->gpio_npins) 341258057Sbr return (EINVAL); 342258057Sbr 343258057Sbr /* Check for unwanted flags. */ 344258057Sbr if ((flags & sc->gpio_pins[i].gp_caps) != flags) 345258057Sbr return (EINVAL); 346258057Sbr 347258057Sbr /* Can't mix input/output together */ 348258057Sbr if ((flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) == 349258057Sbr (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) 350258057Sbr return (EINVAL); 351258057Sbr 352258057Sbr vf_gpio_pin_configure(sc, &sc->gpio_pins[i], flags); 353258057Sbr 354258057Sbr return (0); 355258057Sbr} 356258057Sbr 357258057Sbrstatic int 358258057Sbrvf_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) 359258057Sbr{ 360258057Sbr struct vf_gpio_softc *sc; 361258057Sbr int i; 362258057Sbr 363258057Sbr sc = device_get_softc(dev); 364258057Sbr for (i = 0; i < sc->gpio_npins; i++) { 365258057Sbr if (sc->gpio_pins[i].gp_pin == pin) 366258057Sbr break; 367258057Sbr } 368258057Sbr 369258057Sbr if (i >= sc->gpio_npins) 370258057Sbr return (EINVAL); 371258057Sbr 372258057Sbr GPIO_LOCK(sc); 373258057Sbr if (value) 374258057Sbr WRITE4(sc, GPIO_PSOR(i), (1 << (i % 32))); 375258057Sbr else 376258057Sbr WRITE4(sc, GPIO_PCOR(i), (1 << (i % 32))); 377258057Sbr GPIO_UNLOCK(sc); 378258057Sbr 379258057Sbr return (0); 380258057Sbr} 381258057Sbr 382258057Sbrstatic device_method_t vf_gpio_methods[] = { 383258057Sbr DEVMETHOD(device_probe, vf_gpio_probe), 384258057Sbr DEVMETHOD(device_attach, vf_gpio_attach), 385258057Sbr 386258057Sbr /* GPIO protocol */ 387258057Sbr DEVMETHOD(gpio_pin_max, vf_gpio_pin_max), 388258057Sbr DEVMETHOD(gpio_pin_getname, vf_gpio_pin_getname), 389258057Sbr DEVMETHOD(gpio_pin_getcaps, vf_gpio_pin_getcaps), 390258057Sbr DEVMETHOD(gpio_pin_getflags, vf_gpio_pin_getflags), 391258057Sbr DEVMETHOD(gpio_pin_get, vf_gpio_pin_get), 392258057Sbr DEVMETHOD(gpio_pin_toggle, vf_gpio_pin_toggle), 393258057Sbr DEVMETHOD(gpio_pin_setflags, vf_gpio_pin_setflags), 394258057Sbr DEVMETHOD(gpio_pin_set, vf_gpio_pin_set), 395258057Sbr { 0, 0 } 396258057Sbr}; 397258057Sbr 398258057Sbrstatic driver_t vf_gpio_driver = { 399258057Sbr "gpio", 400258057Sbr vf_gpio_methods, 401258057Sbr sizeof(struct vf_gpio_softc), 402258057Sbr}; 403258057Sbr 404258057Sbrstatic devclass_t vf_gpio_devclass; 405258057Sbr 406258057SbrDRIVER_MODULE(vf_gpio, simplebus, vf_gpio_driver, vf_gpio_devclass, 0, 0); 407