The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/gpio/qoriq_gpio.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2020 Alstom Group.
    3  * Copyright (c) 2020 Semihalf.
    4  * Copyright (c) 2015 Justin Hibbits
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  *
   28  * $FreeBSD$
   29  */
   30 
   31 #include <sys/cdefs.h>
   32 __FBSDID("$FreeBSD$");
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/conf.h>
   37 #include <sys/bus.h>
   38 #include <sys/kernel.h>
   39 #include <sys/module.h>
   40 #include <sys/mutex.h>
   41 #include <sys/rman.h>
   42 #include <sys/gpio.h>
   43 
   44 #include <machine/bus.h>
   45 #include <machine/resource.h>
   46 #include <machine/stdarg.h>
   47 
   48 #include <dev/gpio/gpiobusvar.h>
   49 #include <dev/gpio/qoriq_gpio.h>
   50 #include <dev/ofw/ofw_bus.h>
   51 #include <dev/ofw/ofw_bus_subr.h>
   52 
   53 #include "gpio_if.h"
   54 
   55 static device_t
   56 qoriq_gpio_get_bus(device_t dev)
   57 {
   58         struct qoriq_gpio_softc *sc;
   59 
   60         sc = device_get_softc(dev);
   61 
   62         return (sc->busdev);
   63 }
   64 
   65 static int
   66 qoriq_gpio_pin_max(device_t dev, int *maxpin)
   67 {
   68 
   69         *maxpin = MAXPIN;
   70         return (0);
   71 }
   72 
   73 /* Get a specific pin's capabilities. */
   74 static int
   75 qoriq_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
   76 {
   77         struct qoriq_gpio_softc *sc;
   78 
   79         sc = device_get_softc(dev);
   80 
   81         if (!VALID_PIN(pin))
   82                 return (EINVAL);
   83 
   84         GPIO_LOCK(sc);
   85         *caps = sc->sc_pins[pin].gp_caps;
   86         GPIO_UNLOCK(sc);
   87 
   88         return (0);
   89 }
   90 
   91 /* Get a specific pin's name. */
   92 static int
   93 qoriq_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
   94 {
   95 
   96         if (!VALID_PIN(pin))
   97                 return (EINVAL);
   98 
   99         snprintf(name, GPIOMAXNAME, "qoriq_gpio%d.%d",
  100             device_get_unit(dev), pin);
  101         name[GPIOMAXNAME-1] = '\0';
  102 
  103         return (0);
  104 }
  105 
  106 static int
  107 qoriq_gpio_pin_configure(device_t dev, uint32_t pin, uint32_t flags)
  108 {
  109         struct qoriq_gpio_softc *sc;
  110         uint32_t reg;
  111 
  112         sc = device_get_softc(dev);
  113 
  114         if ((flags & sc->sc_pins[pin].gp_caps) != flags) {
  115                 return (EINVAL);
  116         }
  117 
  118         if (flags & GPIO_PIN_INPUT) {
  119                 reg = bus_read_4(sc->sc_mem, GPIO_GPDIR);
  120                 reg &= ~(1 << (31 - pin));
  121                 bus_write_4(sc->sc_mem, GPIO_GPDIR, reg);
  122         }
  123         else if (flags & GPIO_PIN_OUTPUT) {
  124                 reg = bus_read_4(sc->sc_mem, GPIO_GPDIR);
  125                 reg |= (1 << (31 - pin));
  126                 bus_write_4(sc->sc_mem, GPIO_GPDIR, reg);
  127                 reg = bus_read_4(sc->sc_mem, GPIO_GPODR);
  128                 if (flags & GPIO_PIN_OPENDRAIN)
  129                         reg |= (1 << (31 - pin));
  130                 else
  131                         reg &= ~(1 << (31 - pin));
  132                 bus_write_4(sc->sc_mem, GPIO_GPODR, reg);
  133         }
  134         sc->sc_pins[pin].gp_flags = flags;
  135 
  136         return (0);
  137 }
  138 
  139 /* Set flags for the pin. */
  140 static int
  141 qoriq_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
  142 {
  143         struct qoriq_gpio_softc *sc = device_get_softc(dev);
  144         uint32_t ret;
  145 
  146         if (!VALID_PIN(pin))
  147                 return (EINVAL);
  148 
  149         if ((flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) ==
  150             (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT))
  151                 return (EINVAL);
  152 
  153         GPIO_LOCK(sc);
  154         ret = qoriq_gpio_pin_configure(dev, pin, flags);
  155         GPIO_UNLOCK(sc);
  156         return (ret);
  157 }
  158 
  159 static int
  160 qoriq_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *pflags)
  161 {
  162         struct qoriq_gpio_softc *sc;
  163 
  164         if (!VALID_PIN(pin))
  165                 return (EINVAL);
  166 
  167         sc = device_get_softc(dev);
  168 
  169         GPIO_LOCK(sc);
  170         *pflags = sc->sc_pins[pin].gp_flags;
  171         GPIO_UNLOCK(sc);
  172 
  173         return (0);
  174 }
  175 
  176 /* Set a specific output pin's value. */
  177 static int
  178 qoriq_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
  179 {
  180         struct qoriq_gpio_softc *sc = device_get_softc(dev);
  181         uint32_t outvals;
  182         uint8_t pinbit;
  183 
  184         if (!VALID_PIN(pin) || value > 1)
  185                 return (EINVAL);
  186 
  187         GPIO_LOCK(sc);
  188         pinbit = 31 - pin;
  189 
  190         outvals = bus_read_4(sc->sc_mem, GPIO_GPDAT);
  191         outvals &= ~(1 << pinbit);
  192         outvals |= (value << pinbit);
  193         bus_write_4(sc->sc_mem, GPIO_GPDAT, outvals);
  194 
  195         GPIO_UNLOCK(sc);
  196 
  197         return (0);
  198 }
  199 
  200 /* Get a specific pin's input value. */
  201 static int
  202 qoriq_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *value)
  203 {
  204         struct qoriq_gpio_softc *sc = device_get_softc(dev);
  205 
  206         if (!VALID_PIN(pin))
  207                 return (EINVAL);
  208 
  209         *value = (bus_read_4(sc->sc_mem, GPIO_GPDAT) >> (31 - pin)) & 1;
  210 
  211         return (0);
  212 }
  213 
  214 /* Toggle a pin's output value. */
  215 static int
  216 qoriq_gpio_pin_toggle(device_t dev, uint32_t pin)
  217 {
  218         struct qoriq_gpio_softc *sc = device_get_softc(dev);
  219         uint32_t val;
  220 
  221         if (!VALID_PIN(pin))
  222                 return (EINVAL);
  223 
  224         GPIO_LOCK(sc);
  225 
  226         val = bus_read_4(sc->sc_mem, GPIO_GPDAT);
  227         val ^= (1 << (31 - pin));
  228         bus_write_4(sc->sc_mem, GPIO_GPDAT, val);
  229 
  230         GPIO_UNLOCK(sc);
  231 
  232         return (0);
  233 }
  234 
  235 static struct ofw_compat_data gpio_matches[] = {
  236     {"fsl,pq3-gpio", 1},
  237     {"fsl,mpc8572-gpio", 1},
  238     {"fsl,qoriq-gpio", 1},
  239     {0, 0}
  240 };
  241 
  242 static int
  243 qoriq_gpio_probe(device_t dev)
  244 {
  245 
  246         if (ofw_bus_search_compatible(dev, gpio_matches)->ocd_data == 0)
  247                 return (ENXIO);
  248 
  249         device_set_desc(dev, "Freescale QorIQ GPIO driver");
  250 
  251         return (0);
  252 }
  253 
  254 static int
  255 qoriq_gpio_pin_access_32(device_t dev, uint32_t first_pin, uint32_t clear_pins,
  256     uint32_t change_pins, uint32_t *orig_pins)
  257 {
  258         struct qoriq_gpio_softc *sc;
  259         uint32_t hwstate;
  260 
  261         sc = device_get_softc(dev);
  262 
  263         if (first_pin != 0)
  264                 return (EINVAL);
  265 
  266         GPIO_LOCK(sc);
  267         hwstate = bus_read_4(sc->sc_mem, GPIO_GPDAT);
  268         bus_write_4(sc->sc_mem, GPIO_GPDAT,
  269             (hwstate & ~clear_pins) ^ change_pins);
  270         GPIO_UNLOCK(sc);
  271 
  272         if (orig_pins != NULL)
  273                 *orig_pins = hwstate;
  274 
  275         return (0);
  276 }
  277 
  278 static int
  279 qoriq_gpio_pin_config_32(device_t dev, uint32_t first_pin, uint32_t num_pins,
  280     uint32_t *pin_flags)
  281 {
  282         uint32_t dir, odr, mask, reg;
  283         struct qoriq_gpio_softc *sc;
  284         uint32_t newflags[32];
  285         int i;
  286 
  287         if (first_pin != 0 || !VALID_PIN(num_pins))
  288                 return (EINVAL);
  289 
  290         sc = device_get_softc(dev);
  291 
  292         dir = odr = mask = 0;
  293 
  294         for (i = 0; i < num_pins; i++) {
  295                 newflags[i] = 0;
  296                 mask |= (1 << i);
  297 
  298                 if (pin_flags[i] & GPIO_PIN_INPUT) {
  299                         newflags[i] = GPIO_PIN_INPUT;
  300                         dir &= ~(1 << i);
  301                 } else {
  302                         newflags[i] = GPIO_PIN_OUTPUT;
  303                         dir |= (1 << i);
  304 
  305                         if (pin_flags[i] & GPIO_PIN_OPENDRAIN) {
  306                                 newflags[i] |= GPIO_PIN_OPENDRAIN;
  307                                 odr |= (1 << i);
  308                         } else {
  309                                 newflags[i] |= GPIO_PIN_PUSHPULL;
  310                                 odr &= ~(1 << i);
  311                         }
  312                 }
  313         }
  314 
  315         GPIO_LOCK(sc);
  316 
  317         reg = (bus_read_4(sc->sc_mem, GPIO_GPDIR) & ~mask) | dir;
  318         bus_write_4(sc->sc_mem, GPIO_GPDIR, reg);
  319 
  320         reg = (bus_read_4(sc->sc_mem, GPIO_GPODR) & ~mask) | odr;
  321         bus_write_4(sc->sc_mem, GPIO_GPODR, reg);
  322 
  323         for (i = 0; i < num_pins; i++)
  324                 sc->sc_pins[i].gp_flags = newflags[i];
  325 
  326         GPIO_UNLOCK(sc);
  327 
  328         return (0);
  329 }
  330 
  331 static int
  332 qoriq_gpio_map_gpios(device_t bus, phandle_t dev, phandle_t gparent, int gcells,
  333     pcell_t *gpios, uint32_t *pin, uint32_t *flags)
  334 {
  335         struct qoriq_gpio_softc *sc;
  336         int err;
  337 
  338         if (!VALID_PIN(gpios[0]))
  339                 return (EINVAL);
  340 
  341         sc = device_get_softc(bus);
  342         GPIO_LOCK(sc);
  343         err = qoriq_gpio_pin_configure(bus, gpios[0], gpios[1]);
  344         GPIO_UNLOCK(sc);
  345 
  346         if (err == 0) {
  347                 *pin = gpios[0];
  348                 *flags = gpios[1];
  349         }
  350 
  351         return (err);
  352 }
  353 
  354 int
  355 qoriq_gpio_attach(device_t dev)
  356 {
  357         struct qoriq_gpio_softc *sc = device_get_softc(dev);
  358         int i, rid;
  359 
  360         sc->dev = dev;
  361 
  362         GPIO_LOCK_INIT(sc);
  363 
  364         /* Allocate memory. */
  365         rid = 0;
  366         sc->sc_mem = bus_alloc_resource_any(dev,
  367                      SYS_RES_MEMORY, &rid, RF_ACTIVE);
  368         if (sc->sc_mem == NULL) {
  369                 device_printf(dev, "Can't allocate memory for device output port");
  370                 qoriq_gpio_detach(dev);
  371                 return (ENOMEM);
  372         }
  373 
  374         for (i = 0; i <= MAXPIN; i++)
  375                 sc->sc_pins[i].gp_caps = DEFAULT_CAPS;
  376 
  377         sc->busdev = gpiobus_attach_bus(dev);
  378         if (sc->busdev == NULL) {
  379                 qoriq_gpio_detach(dev);
  380                 return (ENOMEM);
  381         }
  382         /*
  383          * Enable the GPIO Input Buffer for all GPIOs.
  384          * This is safe on devices without a GPIBE register, because those
  385          * devices ignore writes and read 0's in undefined portions of the map.
  386          */
  387         if (ofw_bus_is_compatible(dev, "fsl,qoriq-gpio"))
  388                 bus_write_4(sc->sc_mem, GPIO_GPIBE, 0xffffffff);
  389 
  390         OF_device_register_xref(OF_xref_from_node(ofw_bus_get_node(dev)), dev);
  391 
  392         return (0);
  393 }
  394 
  395 int
  396 qoriq_gpio_detach(device_t dev)
  397 {
  398         struct qoriq_gpio_softc *sc = device_get_softc(dev);
  399 
  400         gpiobus_detach_bus(dev);
  401 
  402         if (sc->sc_mem != NULL) {
  403                 /* Release output port resource. */
  404                 bus_release_resource(dev, SYS_RES_MEMORY,
  405                                      rman_get_rid(sc->sc_mem), sc->sc_mem);
  406         }
  407 
  408         GPIO_LOCK_DESTROY(sc);
  409 
  410         return (0);
  411 }
  412 
  413 static device_method_t qoriq_gpio_methods[] = {
  414         /* device_if */
  415         DEVMETHOD(device_probe,         qoriq_gpio_probe),
  416         DEVMETHOD(device_attach,        qoriq_gpio_attach),
  417         DEVMETHOD(device_detach,        qoriq_gpio_detach),
  418 
  419         /* GPIO protocol */
  420         DEVMETHOD(gpio_get_bus,         qoriq_gpio_get_bus),
  421         DEVMETHOD(gpio_pin_max,         qoriq_gpio_pin_max),
  422         DEVMETHOD(gpio_pin_getname,     qoriq_gpio_pin_getname),
  423         DEVMETHOD(gpio_pin_getcaps,     qoriq_gpio_pin_getcaps),
  424         DEVMETHOD(gpio_pin_get,         qoriq_gpio_pin_get),
  425         DEVMETHOD(gpio_pin_set,         qoriq_gpio_pin_set),
  426         DEVMETHOD(gpio_pin_getflags,    qoriq_gpio_pin_getflags),
  427         DEVMETHOD(gpio_pin_setflags,    qoriq_gpio_pin_setflags),
  428         DEVMETHOD(gpio_pin_toggle,      qoriq_gpio_pin_toggle),
  429 
  430         DEVMETHOD(gpio_map_gpios,       qoriq_gpio_map_gpios),
  431         DEVMETHOD(gpio_pin_access_32,   qoriq_gpio_pin_access_32),
  432         DEVMETHOD(gpio_pin_config_32,   qoriq_gpio_pin_config_32),
  433 
  434         DEVMETHOD_END
  435 };
  436 
  437 DEFINE_CLASS_0(gpio, qoriq_gpio_driver, qoriq_gpio_methods,
  438     sizeof(struct qoriq_gpio_softc));
  439 
  440 EARLY_DRIVER_MODULE(qoriq_gpio, simplebus, qoriq_gpio_driver, NULL, NULL,
  441     BUS_PASS_RESOURCE + BUS_PASS_ORDER_MIDDLE);

Cache object: 9d0efc79b6e4de7402fa026ca9904b73


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.