Path: blob/main/sys/arm/freescale/vybrid/vf_gpio.c
39536 views
/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright (c) 2013 Ruslan Bukin <[email protected]>4* All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11* 2. Redistributions in binary form must reproduce the above copyright12* notice, this list of conditions and the following disclaimer in the13* documentation and/or other materials provided with the distribution.14*15* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND16* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE17* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE18* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE19* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL20* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS21* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)22* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT23* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY24* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF25* SUCH DAMAGE.26*/2728/*29* Vybrid Family General-Purpose Input/Output (GPIO)30* Chapter 7, Vybrid Reference Manual, Rev. 5, 07/201331*/3233#include <sys/param.h>34#include <sys/systm.h>35#include <sys/bus.h>36#include <sys/kernel.h>37#include <sys/module.h>38#include <sys/malloc.h>39#include <sys/rman.h>40#include <sys/timeet.h>41#include <sys/timetc.h>42#include <sys/watchdog.h>43#include <sys/mutex.h>44#include <sys/gpio.h>4546#include <dev/gpio/gpiobusvar.h>47#include <dev/ofw/openfirm.h>48#include <dev/ofw/ofw_bus.h>49#include <dev/ofw/ofw_bus_subr.h>5051#include <machine/bus.h>52#include <machine/cpu.h>53#include <machine/intr.h>5455#include "gpio_if.h"5657#include <arm/freescale/vybrid/vf_common.h>58#include <arm/freescale/vybrid/vf_port.h>5960#define GPIO_PDOR(n) (0x00 + 0x40 * (n >> 5))61#define GPIO_PSOR(n) (0x04 + 0x40 * (n >> 5))62#define GPIO_PCOR(n) (0x08 + 0x40 * (n >> 5))63#define GPIO_PTOR(n) (0x0C + 0x40 * (n >> 5))64#define GPIO_PDIR(n) (0x10 + 0x40 * (n >> 5))6566#define GPIO_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)67#define GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)6869#define DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)7071/*72* GPIO interface73*/74static device_t vf_gpio_get_bus(device_t);75static int vf_gpio_pin_max(device_t, int *);76static int vf_gpio_pin_getcaps(device_t, uint32_t, uint32_t *);77static int vf_gpio_pin_getname(device_t, uint32_t, char *);78static int vf_gpio_pin_getflags(device_t, uint32_t, uint32_t *);79static int vf_gpio_pin_setflags(device_t, uint32_t, uint32_t);80static int vf_gpio_pin_set(device_t, uint32_t, unsigned int);81static int vf_gpio_pin_get(device_t, uint32_t, unsigned int *);82static int vf_gpio_pin_toggle(device_t, uint32_t pin);8384struct vf_gpio_softc {85struct resource *res[1];86bus_space_tag_t bst;87bus_space_handle_t bsh;8889device_t sc_busdev;90struct mtx sc_mtx;91int gpio_npins;92struct gpio_pin gpio_pins[NGPIO];93};9495struct vf_gpio_softc *gpio_sc;9697static struct resource_spec vf_gpio_spec[] = {98{ SYS_RES_MEMORY, 0, RF_ACTIVE },99{ -1, 0 }100};101102static int103vf_gpio_probe(device_t dev)104{105106if (!ofw_bus_status_okay(dev))107return (ENXIO);108109if (!ofw_bus_is_compatible(dev, "fsl,mvf600-gpio"))110return (ENXIO);111112device_set_desc(dev, "Vybrid Family GPIO Unit");113return (BUS_PROBE_DEFAULT);114}115116static int117vf_gpio_attach(device_t dev)118{119struct vf_gpio_softc *sc;120int i;121122sc = device_get_softc(dev);123mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);124125if (bus_alloc_resources(dev, vf_gpio_spec, sc->res)) {126device_printf(dev, "could not allocate resources\n");127mtx_destroy(&sc->sc_mtx);128return (ENXIO);129}130131/* Memory interface */132sc->bst = rman_get_bustag(sc->res[0]);133sc->bsh = rman_get_bushandle(sc->res[0]);134135gpio_sc = sc;136137sc->gpio_npins = NGPIO;138139for (i = 0; i < sc->gpio_npins; i++) {140sc->gpio_pins[i].gp_pin = i;141sc->gpio_pins[i].gp_caps = DEFAULT_CAPS;142sc->gpio_pins[i].gp_flags =143(READ4(sc, GPIO_PDOR(i)) & (1 << (i % 32))) ?144GPIO_PIN_OUTPUT: GPIO_PIN_INPUT;145snprintf(sc->gpio_pins[i].gp_name, GPIOMAXNAME,146"vf_gpio%d.%d", device_get_unit(dev), i);147}148149sc->sc_busdev = gpiobus_add_bus(dev);150if (sc->sc_busdev == NULL) {151bus_release_resources(dev, vf_gpio_spec, sc->res);152mtx_destroy(&sc->sc_mtx);153return (ENXIO);154}155156bus_attach_children(dev);157return (0);158}159160static device_t161vf_gpio_get_bus(device_t dev)162{163struct vf_gpio_softc *sc;164165sc = device_get_softc(dev);166167return (sc->sc_busdev);168}169170static int171vf_gpio_pin_max(device_t dev, int *maxpin)172{173174*maxpin = NGPIO - 1;175return (0);176}177178static int179vf_gpio_pin_getname(device_t dev, uint32_t pin, char *name)180{181struct vf_gpio_softc *sc;182int i;183184sc = device_get_softc(dev);185for (i = 0; i < sc->gpio_npins; i++) {186if (sc->gpio_pins[i].gp_pin == pin)187break;188}189190if (i >= sc->gpio_npins)191return (EINVAL);192193GPIO_LOCK(sc);194memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME);195GPIO_UNLOCK(sc);196197return (0);198}199200static int201vf_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)202{203struct vf_gpio_softc *sc;204int i;205206sc = device_get_softc(dev);207for (i = 0; i < sc->gpio_npins; i++) {208if (sc->gpio_pins[i].gp_pin == pin)209break;210}211212if (i >= sc->gpio_npins)213return (EINVAL);214215GPIO_LOCK(sc);216*caps = sc->gpio_pins[i].gp_caps;217GPIO_UNLOCK(sc);218219return (0);220}221222static int223vf_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)224{225struct vf_gpio_softc *sc;226int i;227228sc = device_get_softc(dev);229for (i = 0; i < sc->gpio_npins; i++) {230if (sc->gpio_pins[i].gp_pin == pin)231break;232}233234if (i >= sc->gpio_npins)235return (EINVAL);236237GPIO_LOCK(sc);238*flags = sc->gpio_pins[i].gp_flags;239GPIO_UNLOCK(sc);240241return (0);242}243244static int245vf_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)246{247struct vf_gpio_softc *sc;248int i;249250sc = device_get_softc(dev);251for (i = 0; i < sc->gpio_npins; i++) {252if (sc->gpio_pins[i].gp_pin == pin)253break;254}255256if (i >= sc->gpio_npins)257return (EINVAL);258259GPIO_LOCK(sc);260*val = (READ4(sc, GPIO_PDIR(i)) & (1 << (i % 32))) ? 1 : 0;261GPIO_UNLOCK(sc);262263return (0);264}265266static int267vf_gpio_pin_toggle(device_t dev, uint32_t pin)268{269struct vf_gpio_softc *sc;270int i;271272sc = device_get_softc(dev);273for (i = 0; i < sc->gpio_npins; i++) {274if (sc->gpio_pins[i].gp_pin == pin)275break;276}277278if (i >= sc->gpio_npins)279return (EINVAL);280281GPIO_LOCK(sc);282WRITE4(sc, GPIO_PTOR(i), (1 << (i % 32)));283GPIO_UNLOCK(sc);284285return (0);286}287288static void289vf_gpio_pin_configure(struct vf_gpio_softc *sc, struct gpio_pin *pin,290unsigned int flags)291{292293GPIO_LOCK(sc);294295/*296* Manage input/output297*/298if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) {299pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT);300if (flags & GPIO_PIN_OUTPUT) {301pin->gp_flags |= GPIO_PIN_OUTPUT;302303} else {304pin->gp_flags |= GPIO_PIN_INPUT;305WRITE4(sc, GPIO_PCOR(pin->gp_pin),306(1 << (pin->gp_pin % 32)));307}308}309310GPIO_UNLOCK(sc);311}312313static int314vf_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)315{316struct vf_gpio_softc *sc;317int i;318319sc = device_get_softc(dev);320for (i = 0; i < sc->gpio_npins; i++) {321if (sc->gpio_pins[i].gp_pin == pin)322break;323}324325if (i >= sc->gpio_npins)326return (EINVAL);327328vf_gpio_pin_configure(sc, &sc->gpio_pins[i], flags);329330return (0);331}332333static int334vf_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)335{336struct vf_gpio_softc *sc;337int i;338339sc = device_get_softc(dev);340for (i = 0; i < sc->gpio_npins; i++) {341if (sc->gpio_pins[i].gp_pin == pin)342break;343}344345if (i >= sc->gpio_npins)346return (EINVAL);347348GPIO_LOCK(sc);349if (value)350WRITE4(sc, GPIO_PSOR(i), (1 << (i % 32)));351else352WRITE4(sc, GPIO_PCOR(i), (1 << (i % 32)));353GPIO_UNLOCK(sc);354355return (0);356}357358static device_method_t vf_gpio_methods[] = {359DEVMETHOD(device_probe, vf_gpio_probe),360DEVMETHOD(device_attach, vf_gpio_attach),361362/* GPIO protocol */363DEVMETHOD(gpio_get_bus, vf_gpio_get_bus),364DEVMETHOD(gpio_pin_max, vf_gpio_pin_max),365DEVMETHOD(gpio_pin_getname, vf_gpio_pin_getname),366DEVMETHOD(gpio_pin_getcaps, vf_gpio_pin_getcaps),367DEVMETHOD(gpio_pin_getflags, vf_gpio_pin_getflags),368DEVMETHOD(gpio_pin_get, vf_gpio_pin_get),369DEVMETHOD(gpio_pin_toggle, vf_gpio_pin_toggle),370DEVMETHOD(gpio_pin_setflags, vf_gpio_pin_setflags),371DEVMETHOD(gpio_pin_set, vf_gpio_pin_set),372{ 0, 0 }373};374375static driver_t vf_gpio_driver = {376"gpio",377vf_gpio_methods,378sizeof(struct vf_gpio_softc),379};380381DRIVER_MODULE(vf_gpio, simplebus, vf_gpio_driver, 0, 0);382383384