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/riscv/sifive/sifive_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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2021 Jessica Clarke <jrtc27@FreeBSD.org>
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  *
   27  */
   28 
   29 /* TODO: Provide interrupt controller interface */
   30 
   31 #include <sys/cdefs.h>
   32 __FBSDID("$FreeBSD$");
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/bus.h>
   37 #include <sys/kernel.h>
   38 #include <sys/module.h>
   39 #include <sys/rman.h>
   40 #include <sys/lock.h>
   41 #include <sys/mutex.h>
   42 #include <sys/gpio.h>
   43 
   44 #include <dev/gpio/gpiobusvar.h>
   45 #include <dev/ofw/ofw_bus.h>
   46 #include <dev/ofw/ofw_bus_subr.h>
   47 
   48 #include <machine/bus.h>
   49 
   50 /* Registers are 32-bit so can only fit 32 pins */
   51 #define SFGPIO_MAX_PINS         32
   52 
   53 #define SFGPIO_DEFAULT_CAPS     (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)
   54 
   55 #define SFGPIO_INPUT_VAL        0x0
   56 #define SFGPIO_INPUT_EN         0x4
   57 #define SFGPIO_OUTPUT_EN        0x8
   58 #define SFGPIO_OUTPUT_VAL       0xc
   59 #define SFGPIO_RISE_IE          0x18
   60 #define SFGPIO_RISE_IP          0x1c
   61 #define SFGPIO_FALL_IE          0x20
   62 #define SFGPIO_FALL_IP          0x24
   63 #define SFGPIO_HIGH_IE          0x28
   64 #define SFGPIO_HIGH_IP          0x2c
   65 #define SFGPIO_LOW_IE           0x30
   66 #define SFGPIO_LOW_IP           0x34
   67 
   68 struct sfgpio_softc {
   69         device_t        dev;
   70         device_t        busdev;
   71         struct mtx      mtx;
   72         struct resource *mem_res;
   73         int             mem_rid;
   74         struct resource *irq_res;
   75         int             irq_rid;
   76         int             npins;
   77         struct gpio_pin gpio_pins[SFGPIO_MAX_PINS];
   78 };
   79 
   80 #define SFGPIO_LOCK(_sc)        mtx_lock(&(_sc)->mtx)
   81 #define SFGPIO_UNLOCK(_sc)      mtx_unlock(&(_sc)->mtx)
   82 
   83 #define SFGPIO_READ(_sc, _off)          \
   84     bus_read_4((_sc)->mem_res, (_off))
   85 #define SFGPIO_WRITE(_sc, _off, _val)   \
   86     bus_write_4((_sc)->mem_res, (_off), (_val))
   87 
   88 static struct ofw_compat_data compat_data[] = {
   89         { "sifive,gpio0",       1 },
   90         { NULL,                 0 },
   91 };
   92 
   93 static int
   94 sfgpio_probe(device_t dev)
   95 {
   96         if (!ofw_bus_status_okay(dev))
   97                 return (ENXIO);
   98 
   99         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
  100                 return (ENXIO);
  101 
  102         device_set_desc(dev, "SiFive GPIO Controller");
  103 
  104         return (BUS_PROBE_DEFAULT);
  105 }
  106 
  107 static int
  108 sfgpio_attach(device_t dev)
  109 {
  110         struct sfgpio_softc *sc;
  111         phandle_t node;
  112         int error, i;
  113         pcell_t npins;
  114         uint32_t input_en, output_en;
  115 
  116         sc = device_get_softc(dev);
  117         sc->dev = dev;
  118 
  119         node = ofw_bus_get_node(dev);
  120 
  121         mtx_init(&sc->mtx, device_get_nameunit(sc->dev), NULL, MTX_DEF);
  122 
  123         sc->mem_rid = 0;
  124         sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
  125             &sc->mem_rid, RF_ACTIVE);
  126         if (sc->mem_res == NULL) {
  127                 device_printf(dev, "Cannot allocate memory resource\n");
  128                 error = ENXIO;
  129                 goto fail;
  130         }
  131 
  132         if (OF_getencprop(node, "ngpios", &npins, sizeof(npins)) <= 0) {
  133                 /* Optional; defaults to 16 */
  134                 npins = 16;
  135         } else if (npins > SFGPIO_MAX_PINS) {
  136                 device_printf(dev, "Too many pins: %d\n", npins);
  137                 error = ENXIO;
  138                 goto fail;
  139         }
  140         sc->npins = npins;
  141 
  142         sc->irq_rid = 0;
  143         sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid,
  144             RF_ACTIVE);
  145         if (sc->irq_res == NULL) {
  146                 device_printf(dev, "Cannot allocate IRQ resource\n");
  147                 error = ENXIO;
  148                 goto fail;
  149         }
  150 
  151         input_en = SFGPIO_READ(sc, SFGPIO_INPUT_EN);
  152         output_en = SFGPIO_READ(sc, SFGPIO_OUTPUT_EN);
  153         for (i = 0; i < sc->npins; ++i) {
  154                 sc->gpio_pins[i].gp_pin = i;
  155                 sc->gpio_pins[i].gp_caps = SFGPIO_DEFAULT_CAPS;
  156                 sc->gpio_pins[i].gp_flags =
  157                     ((input_en & (1u << i)) ? GPIO_PIN_INPUT : 0) |
  158                     ((output_en & (1u << i)) ? GPIO_PIN_OUTPUT : 0);
  159                 snprintf(sc->gpio_pins[i].gp_name, GPIOMAXNAME, "GPIO%d", i);
  160                 sc->gpio_pins[i].gp_name[GPIOMAXNAME - 1] = '\0';
  161         }
  162 
  163         sc->busdev = gpiobus_attach_bus(dev);
  164         if (sc->busdev == NULL) {
  165                 device_printf(dev, "Cannot attach gpiobus\n");
  166                 error = ENXIO;
  167                 goto fail;
  168         }
  169 
  170         return (0);
  171 
  172 fail:
  173         if (sc->busdev != NULL)
  174                 gpiobus_detach_bus(dev);
  175         if (sc->irq_res != NULL)
  176                 bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid,
  177                     sc->irq_res);
  178         if (sc->mem_res != NULL)
  179                 bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid,
  180                     sc->mem_res);
  181         mtx_destroy(&sc->mtx);
  182         return (error);
  183 }
  184 
  185 static device_t
  186 sfgpio_get_bus(device_t dev)
  187 {
  188         struct sfgpio_softc *sc;
  189 
  190         sc = device_get_softc(dev);
  191 
  192         return (sc->busdev);
  193 }
  194 
  195 static int
  196 sfgpio_pin_max(device_t dev, int *maxpin)
  197 {
  198         struct sfgpio_softc *sc;
  199 
  200         sc = device_get_softc(dev);
  201 
  202         *maxpin = sc->npins - 1;
  203 
  204         return (0);
  205 }
  206 
  207 static int
  208 sfgpio_pin_set(device_t dev, uint32_t pin, unsigned int val)
  209 {
  210         struct sfgpio_softc *sc;
  211         uint32_t reg;
  212 
  213         sc = device_get_softc(dev);
  214 
  215         if (pin >= sc->npins)
  216                 return (EINVAL);
  217 
  218         SFGPIO_LOCK(sc);
  219         reg = SFGPIO_READ(sc, SFGPIO_OUTPUT_VAL);
  220         if (val)
  221                 reg |= (1u << pin);
  222         else
  223                 reg &= ~(1u << pin);
  224         SFGPIO_WRITE(sc, SFGPIO_OUTPUT_VAL, reg);
  225         SFGPIO_UNLOCK(sc);
  226 
  227         return (0);
  228 }
  229 
  230 static int
  231 sfgpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
  232 {
  233         struct sfgpio_softc *sc;
  234         uint32_t reg;
  235 
  236         sc = device_get_softc(dev);
  237 
  238         if (pin >= sc->npins)
  239                 return (EINVAL);
  240 
  241         SFGPIO_LOCK(sc);
  242         if (sc->gpio_pins[pin].gp_flags & GPIO_PIN_OUTPUT)
  243                 reg = SFGPIO_READ(sc, SFGPIO_OUTPUT_VAL);
  244         else
  245                 reg = SFGPIO_READ(sc, SFGPIO_INPUT_VAL);
  246         *val = (reg & (1u << pin)) ? 1 : 0;
  247         SFGPIO_UNLOCK(sc);
  248 
  249         return (0);
  250 }
  251 
  252 static int
  253 sfgpio_pin_toggle(device_t dev, uint32_t pin)
  254 {
  255         struct sfgpio_softc *sc;
  256         uint32_t reg;
  257 
  258         sc = device_get_softc(dev);
  259 
  260         if (pin >= sc->npins)
  261                 return (EINVAL);
  262 
  263         SFGPIO_LOCK(sc);
  264         reg = SFGPIO_READ(sc, SFGPIO_OUTPUT_VAL);
  265         reg ^= (1u << pin);
  266         SFGPIO_WRITE(sc, SFGPIO_OUTPUT_VAL, reg);
  267         SFGPIO_UNLOCK(sc);
  268 
  269         return (0);
  270 }
  271 
  272 static int
  273 sfgpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
  274 {
  275         struct sfgpio_softc *sc;
  276 
  277         sc = device_get_softc(dev);
  278 
  279         if (pin >= sc->npins)
  280                 return (EINVAL);
  281 
  282         SFGPIO_LOCK(sc);
  283         *caps = sc->gpio_pins[pin].gp_caps;
  284         SFGPIO_UNLOCK(sc);
  285 
  286         return (0);
  287 }
  288 
  289 static int
  290 sfgpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
  291 {
  292         struct sfgpio_softc *sc;
  293 
  294         sc = device_get_softc(dev);
  295 
  296         if (pin >= sc->npins)
  297                 return (EINVAL);
  298 
  299         SFGPIO_LOCK(sc);
  300         *flags = sc->gpio_pins[pin].gp_flags;
  301         SFGPIO_UNLOCK(sc);
  302 
  303         return (0);
  304 }
  305 
  306 static int
  307 sfgpio_pin_getname(device_t dev, uint32_t pin, char *name)
  308 {
  309         struct sfgpio_softc *sc;
  310 
  311         sc = device_get_softc(dev);
  312 
  313         if (pin >= sc->npins)
  314                 return (EINVAL);
  315 
  316         SFGPIO_LOCK(sc);
  317         memcpy(name, sc->gpio_pins[pin].gp_name, GPIOMAXNAME);
  318         SFGPIO_UNLOCK(sc);
  319 
  320         return (0);
  321 }
  322 
  323 static int
  324 sfgpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
  325 {
  326         struct sfgpio_softc *sc;
  327         uint32_t reg;
  328 
  329         sc = device_get_softc(dev);
  330 
  331         if (pin >= sc->npins)
  332                 return (EINVAL);
  333 
  334         SFGPIO_LOCK(sc);
  335 
  336         reg = SFGPIO_READ(sc, SFGPIO_INPUT_EN);
  337         if (flags & GPIO_PIN_INPUT) {
  338                 reg |= (1u << pin);
  339                 sc->gpio_pins[pin].gp_flags |= GPIO_PIN_INPUT;
  340         } else {
  341                 reg &= ~(1u << pin);
  342                 sc->gpio_pins[pin].gp_flags &= ~GPIO_PIN_INPUT;
  343         }
  344         SFGPIO_WRITE(sc, SFGPIO_INPUT_EN, reg);
  345 
  346         reg = SFGPIO_READ(sc, SFGPIO_OUTPUT_EN);
  347         if (flags & GPIO_PIN_OUTPUT) {
  348                 reg |= (1u << pin);
  349                 sc->gpio_pins[pin].gp_flags |= GPIO_PIN_OUTPUT;
  350         } else {
  351                 reg &= ~(1u << pin);
  352                 sc->gpio_pins[pin].gp_flags &= ~GPIO_PIN_OUTPUT;
  353         }
  354         SFGPIO_WRITE(sc, SFGPIO_OUTPUT_EN, reg);
  355 
  356         SFGPIO_UNLOCK(sc);
  357 
  358         return (0);
  359 }
  360 
  361 static int
  362 sfgpio_pin_access_32(device_t dev, uint32_t first_pin, uint32_t clear_pins,
  363     uint32_t change_pins, uint32_t *orig_pins)
  364 {
  365         struct sfgpio_softc *sc;
  366         uint32_t reg;
  367 
  368         if (first_pin != 0)
  369                 return (EINVAL);
  370 
  371         sc = device_get_softc(dev);
  372 
  373         SFGPIO_LOCK(sc);
  374 
  375         reg = SFGPIO_READ(sc, SFGPIO_OUTPUT_VAL);
  376 
  377         if (orig_pins != NULL)
  378                 /* Only input_val is implicitly masked by input_en */
  379                 *orig_pins = SFGPIO_READ(sc, SFGPIO_INPUT_VAL) |
  380                      (reg & SFGPIO_READ(sc, SFGPIO_OUTPUT_EN));
  381 
  382         if ((clear_pins | change_pins) != 0)
  383                 SFGPIO_WRITE(sc, SFGPIO_OUTPUT_VAL,
  384                     (reg & ~clear_pins) ^ change_pins);
  385 
  386         SFGPIO_UNLOCK(sc);
  387 
  388         return (0);
  389 }
  390 
  391 static int
  392 sfgpio_pin_config_32(device_t dev, uint32_t first_pin, uint32_t num_pins,
  393     uint32_t *pin_flags)
  394 {
  395         struct sfgpio_softc *sc;
  396         uint32_t ireg, oreg;
  397         int i;
  398 
  399         sc = device_get_softc(dev);
  400 
  401         if (first_pin != 0 || num_pins > sc->npins)
  402                 return (EINVAL);
  403 
  404         SFGPIO_LOCK(sc);
  405 
  406         ireg = SFGPIO_READ(sc, SFGPIO_INPUT_EN);
  407         oreg = SFGPIO_READ(sc, SFGPIO_OUTPUT_EN);
  408         for (i = 0; i < num_pins; ++i) {
  409                 if (pin_flags[i] & GPIO_PIN_INPUT) {
  410                         ireg |= (1u << i);
  411                         oreg &= ~(1u << i);
  412                         sc->gpio_pins[i].gp_flags |= GPIO_PIN_INPUT;
  413                         sc->gpio_pins[i].gp_flags &= ~GPIO_PIN_OUTPUT;
  414                 } else if (pin_flags[i] & GPIO_PIN_OUTPUT) {
  415                         ireg &= ~(1u << i);
  416                         oreg |= (1u << i);
  417                         sc->gpio_pins[i].gp_flags &= ~GPIO_PIN_INPUT;
  418                         sc->gpio_pins[i].gp_flags |= GPIO_PIN_OUTPUT;
  419                 }
  420         }
  421         SFGPIO_WRITE(sc, SFGPIO_INPUT_EN, ireg);
  422         SFGPIO_WRITE(sc, SFGPIO_OUTPUT_EN, oreg);
  423 
  424         SFGPIO_UNLOCK(sc);
  425 
  426         return (0);
  427 }
  428 
  429 static phandle_t
  430 sfgpio_get_node(device_t bus, device_t dev)
  431 {
  432         return (ofw_bus_get_node(bus));
  433 }
  434 
  435 static device_method_t sfgpio_methods[] = {
  436         /* Device interface */
  437         DEVMETHOD(device_probe,         sfgpio_probe),
  438         DEVMETHOD(device_attach,        sfgpio_attach),
  439 
  440         /* GPIO protocol */
  441         DEVMETHOD(gpio_get_bus,         sfgpio_get_bus),
  442         DEVMETHOD(gpio_pin_max,         sfgpio_pin_max),
  443         DEVMETHOD(gpio_pin_set,         sfgpio_pin_set),
  444         DEVMETHOD(gpio_pin_get,         sfgpio_pin_get),
  445         DEVMETHOD(gpio_pin_toggle,      sfgpio_pin_toggle),
  446         DEVMETHOD(gpio_pin_getcaps,     sfgpio_pin_getcaps),
  447         DEVMETHOD(gpio_pin_getflags,    sfgpio_pin_getflags),
  448         DEVMETHOD(gpio_pin_getname,     sfgpio_pin_getname),
  449         DEVMETHOD(gpio_pin_setflags,    sfgpio_pin_setflags),
  450         DEVMETHOD(gpio_pin_access_32,   sfgpio_pin_access_32),
  451         DEVMETHOD(gpio_pin_config_32,   sfgpio_pin_config_32),
  452 
  453         /* ofw_bus interface */
  454         DEVMETHOD(ofw_bus_get_node,     sfgpio_get_node),
  455 
  456         DEVMETHOD_END
  457 };
  458 
  459 DEFINE_CLASS_0(gpio, sfgpio_driver, sfgpio_methods,
  460     sizeof(struct sfgpio_softc));
  461 EARLY_DRIVER_MODULE(gpio, simplebus, sfgpio_driver, 0, 0,
  462     BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE);
  463 MODULE_DEPEND(sfgpio, gpiobus, 1, 1, 1);

Cache object: 072c3c4cef84ed48f699c89287ff8cd8


[ 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.