Path: blob/main/sys/powerpc/mpc85xx/mpc85xx_gpio.c
39507 views
/*-1* Copyright (c) 2015 Justin Hibbits2* Copyright (c) 2013 Thomas Skibo3* All rights reserved.4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions7* are met:8* 1. Redistributions of source code must retain the above copyright9* notice, this list of conditions and the following disclaimer.10* 2. Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13*14* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND15* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE16* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE17* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE18* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL19* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS20* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)21* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT22* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY23* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF24* SUCH DAMAGE.25*/2627#include <sys/param.h>28#include <sys/systm.h>29#include <sys/conf.h>30#include <sys/bus.h>31#include <sys/kernel.h>32#include <sys/module.h>33#include <sys/lock.h>34#include <sys/mutex.h>35#include <sys/resource.h>36#include <sys/rman.h>37#include <sys/gpio.h>38#include <sys/stdarg.h>3940#include <machine/bus.h>41#include <machine/resource.h>4243#include <dev/fdt/fdt_common.h>44#include <dev/gpio/gpiobusvar.h>45#include <dev/ofw/ofw_bus.h>46#include <dev/ofw/ofw_bus_subr.h>4748#include "gpio_if.h"4950#define MAXPIN (7)5152#define VALID_PIN(u) ((u) >= 0 && (u) <= MAXPIN)5354#define GPIO_LOCK(sc) mtx_lock(&(sc)->sc_mtx)55#define GPIO_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx)56#define GPIO_LOCK_INIT(sc) \57mtx_init(&(sc)->sc_mtx, device_get_nameunit((sc)->dev), \58"gpio", MTX_DEF)59#define GPIO_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx);6061struct mpc85xx_gpio_softc {62device_t dev;63device_t busdev;64struct mtx sc_mtx;65struct resource *out_res; /* Memory resource */66struct resource *in_res;67};6869static device_t70mpc85xx_gpio_get_bus(device_t dev)71{72struct mpc85xx_gpio_softc *sc;7374sc = device_get_softc(dev);7576return (sc->busdev);77}7879static int80mpc85xx_gpio_pin_max(device_t dev, int *maxpin)81{8283*maxpin = MAXPIN;84return (0);85}8687/* Get a specific pin's capabilities. */88static int89mpc85xx_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)90{9192if (!VALID_PIN(pin))93return (EINVAL);9495*caps = (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT);9697return (0);98}99100/* Get a specific pin's name. */101static int102mpc85xx_gpio_pin_getname(device_t dev, uint32_t pin, char *name)103{104105if (!VALID_PIN(pin))106return (EINVAL);107108snprintf(name, GPIOMAXNAME, "GPIO%d", pin);109name[GPIOMAXNAME-1] = '\0';110111return (0);112}113114/* Set a specific output pin's value. */115static int116mpc85xx_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)117{118struct mpc85xx_gpio_softc *sc = device_get_softc(dev);119uint32_t outvals;120uint8_t pinbit;121122if (!VALID_PIN(pin) || value > 1)123return (EINVAL);124125GPIO_LOCK(sc);126pinbit = 31 - pin;127128outvals = bus_read_4(sc->out_res, 0);129outvals &= ~(1 << pinbit);130outvals |= (value << pinbit);131bus_write_4(sc->out_res, 0, outvals);132133GPIO_UNLOCK(sc);134135return (0);136}137138/* Get a specific pin's input value. */139static int140mpc85xx_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *value)141{142struct mpc85xx_gpio_softc *sc = device_get_softc(dev);143144if (!VALID_PIN(pin))145return (EINVAL);146147*value = (bus_read_4(sc->in_res, 0) >> (31 - pin)) & 1;148149return (0);150}151152/* Toggle a pin's output value. */153static int154mpc85xx_gpio_pin_toggle(device_t dev, uint32_t pin)155{156struct mpc85xx_gpio_softc *sc = device_get_softc(dev);157uint32_t val;158159if (!VALID_PIN(pin))160return (EINVAL);161162GPIO_LOCK(sc);163164val = bus_read_4(sc->out_res, 0);165val ^= (1 << (31 - pin));166bus_write_4(sc->out_res, 0, val);167168GPIO_UNLOCK(sc);169170return (0);171}172173static int174mpc85xx_gpio_probe(device_t dev)175{176uint32_t svr;177178if (!ofw_bus_status_okay(dev))179return (ENXIO);180181if (!ofw_bus_is_compatible(dev, "gpio"))182return (ENXIO);183184svr = mfspr(SPR_SVR);185switch (SVR_VER(svr)) {186case SVR_MPC8533:187case SVR_MPC8533E:188break;189default:190return (ENXIO);191}192193device_set_desc(dev, "MPC85xx GPIO driver");194return (0);195}196197static int mpc85xx_gpio_detach(device_t dev);198199static int200mpc85xx_gpio_attach(device_t dev)201{202struct mpc85xx_gpio_softc *sc = device_get_softc(dev);203int rid;204205sc->dev = dev;206207GPIO_LOCK_INIT(sc);208209/* Allocate memory. */210rid = 0;211sc->out_res = bus_alloc_resource_any(dev,212SYS_RES_MEMORY, &rid, RF_ACTIVE);213if (sc->out_res == NULL) {214device_printf(dev, "Can't allocate memory for device output port");215mpc85xx_gpio_detach(dev);216return (ENOMEM);217}218219rid = 1;220sc->in_res = bus_alloc_resource_any(dev,221SYS_RES_MEMORY, &rid, RF_ACTIVE);222if (sc->in_res == NULL) {223device_printf(dev, "Can't allocate memory for device input port");224mpc85xx_gpio_detach(dev);225return (ENOMEM);226}227228OF_device_register_xref(OF_xref_from_node(ofw_bus_get_node(dev)), dev);229230sc->busdev = gpiobus_add_bus(dev);231if (sc->busdev == NULL) {232mpc85xx_gpio_detach(dev);233return (ENOMEM);234}235236bus_attach_children(dev);237return (0);238}239240static int241mpc85xx_gpio_detach(device_t dev)242{243struct mpc85xx_gpio_softc *sc = device_get_softc(dev);244245gpiobus_detach_bus(dev);246247if (sc->out_res != NULL) {248/* Release output port resource. */249bus_release_resource(dev, SYS_RES_MEMORY,250rman_get_rid(sc->out_res), sc->out_res);251}252253if (sc->in_res != NULL) {254/* Release input port resource. */255bus_release_resource(dev, SYS_RES_MEMORY,256rman_get_rid(sc->in_res), sc->in_res);257}258259GPIO_LOCK_DESTROY(sc);260261return (0);262}263264static device_method_t mpc85xx_gpio_methods[] = {265/* device_if */266DEVMETHOD(device_probe, mpc85xx_gpio_probe),267DEVMETHOD(device_attach, mpc85xx_gpio_attach),268DEVMETHOD(device_detach, mpc85xx_gpio_detach),269270/* GPIO protocol */271DEVMETHOD(gpio_get_bus, mpc85xx_gpio_get_bus),272DEVMETHOD(gpio_pin_max, mpc85xx_gpio_pin_max),273DEVMETHOD(gpio_pin_getname, mpc85xx_gpio_pin_getname),274DEVMETHOD(gpio_pin_getcaps, mpc85xx_gpio_pin_getcaps),275DEVMETHOD(gpio_pin_get, mpc85xx_gpio_pin_get),276DEVMETHOD(gpio_pin_set, mpc85xx_gpio_pin_set),277DEVMETHOD(gpio_pin_toggle, mpc85xx_gpio_pin_toggle),278279DEVMETHOD_END280};281282static driver_t mpc85xx_gpio_driver = {283"gpio",284mpc85xx_gpio_methods,285sizeof(struct mpc85xx_gpio_softc),286};287288EARLY_DRIVER_MODULE(mpc85xx_gpio, simplebus, mpc85xx_gpio_driver, NULL, NULL,289BUS_PASS_RESOURCE + BUS_PASS_ORDER_MIDDLE);290291292