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/arm/allwinner/a10_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) 2013 Ganbold Tsagaankhuu <ganbold@freebsd.org>
    3  * Copyright (c) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org>
    4  * Copyright (c) 2012 Luiz Otavio O Souza.
    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  */
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD: releng/10.2/sys/arm/allwinner/a10_gpio.c 278786 2015-02-14 21:16:19Z loos $");
   31 
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 #include <sys/bus.h>
   35 
   36 #include <sys/kernel.h>
   37 #include <sys/module.h>
   38 #include <sys/rman.h>
   39 #include <sys/lock.h>
   40 #include <sys/mutex.h>
   41 #include <sys/gpio.h>
   42 
   43 #include <machine/bus.h>
   44 #include <machine/cpu.h>
   45 #include <machine/cpufunc.h>
   46 #include <machine/resource.h>
   47 #include <machine/fdt.h>
   48 #include <machine/intr.h>
   49 
   50 #include <dev/fdt/fdt_common.h>
   51 #include <dev/ofw/ofw_bus.h>
   52 #include <dev/ofw/ofw_bus_subr.h>
   53 
   54 #include "gpio_if.h"
   55 #include "a10_gpio.h"
   56 
   57 /*
   58  * A10 have 9 banks of gpio.
   59  * 32 pins per bank:
   60  * PA0 - PA17 | PB0 - PB23 | PC0 - PC24
   61  * PD0 - PD27 | PE0 - PE31 | PF0 - PF5
   62  * PG0 - PG9 | PH0 - PH27 | PI0 - PI12
   63  */
   64 
   65 #define A10_GPIO_PINS           288
   66 #define A10_GPIO_DEFAULT_CAPS   (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT |     \
   67     GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN)
   68 
   69 #define A10_GPIO_NONE           0
   70 #define A10_GPIO_PULLUP         1
   71 #define A10_GPIO_PULLDOWN       2
   72 
   73 #define A10_GPIO_INPUT          0
   74 #define A10_GPIO_OUTPUT         1
   75 
   76 struct a10_gpio_softc {
   77         device_t                sc_dev;
   78         struct mtx              sc_mtx;
   79         struct resource *       sc_mem_res;
   80         struct resource *       sc_irq_res;
   81         bus_space_tag_t         sc_bst;
   82         bus_space_handle_t      sc_bsh;
   83         void *                  sc_intrhand;
   84         int                     sc_gpio_npins;
   85         struct gpio_pin         sc_gpio_pins[A10_GPIO_PINS];
   86 };
   87 
   88 #define A10_GPIO_LOCK(_sc)              mtx_lock(&_sc->sc_mtx)
   89 #define A10_GPIO_UNLOCK(_sc)            mtx_unlock(&_sc->sc_mtx)
   90 #define A10_GPIO_LOCK_ASSERT(_sc)       mtx_assert(&_sc->sc_mtx, MA_OWNED)
   91 
   92 #define A10_GPIO_GP_CFG(_bank, _pin)    0x00 + ((_bank) * 0x24) + ((_pin)<<2)
   93 #define A10_GPIO_GP_DAT(_bank)          0x10 + ((_bank) * 0x24)
   94 #define A10_GPIO_GP_DRV(_bank, _pin)    0x14 + ((_bank) * 0x24) + ((_pin)<<2)
   95 #define A10_GPIO_GP_PUL(_bank, _pin)    0x1c + ((_bank) * 0x24) + ((_pin)<<2)
   96 
   97 #define A10_GPIO_GP_INT_CFG0            0x200
   98 #define A10_GPIO_GP_INT_CFG1            0x204
   99 #define A10_GPIO_GP_INT_CFG2            0x208
  100 #define A10_GPIO_GP_INT_CFG3            0x20c
  101 
  102 #define A10_GPIO_GP_INT_CTL             0x210
  103 #define A10_GPIO_GP_INT_STA             0x214
  104 #define A10_GPIO_GP_INT_DEB             0x218
  105 
  106 static struct a10_gpio_softc *a10_gpio_sc;
  107 
  108 #define A10_GPIO_WRITE(_sc, _off, _val)         \
  109     bus_space_write_4(_sc->sc_bst, _sc->sc_bsh, _off, _val)
  110 #define A10_GPIO_READ(_sc, _off)                \
  111     bus_space_read_4(_sc->sc_bst, _sc->sc_bsh, _off)
  112 
  113 static uint32_t
  114 a10_gpio_get_function(struct a10_gpio_softc *sc, uint32_t pin)
  115 {
  116         uint32_t bank, func, offset;
  117 
  118         bank = pin / 32;
  119         pin = pin - 32 * bank;
  120         func = pin >> 3;
  121         offset = ((pin & 0x07) << 2);
  122 
  123         A10_GPIO_LOCK(sc);
  124         func = (A10_GPIO_READ(sc, A10_GPIO_GP_CFG(bank, func)) >> offset) & 7;
  125         A10_GPIO_UNLOCK(sc);
  126 
  127         return (func);
  128 }
  129 
  130 static uint32_t
  131 a10_gpio_func_flag(uint32_t nfunc)
  132 {
  133 
  134         switch (nfunc) {
  135         case A10_GPIO_INPUT:
  136                 return (GPIO_PIN_INPUT);
  137         case A10_GPIO_OUTPUT:
  138                 return (GPIO_PIN_OUTPUT);
  139         }
  140         return (0);
  141 }
  142 
  143 static void
  144 a10_gpio_set_function(struct a10_gpio_softc *sc, uint32_t pin, uint32_t f)
  145 {
  146         uint32_t bank, func, data, offset;
  147 
  148         /* Must be called with lock held. */
  149         A10_GPIO_LOCK_ASSERT(sc);
  150 
  151         bank = pin / 32;
  152         pin = pin - 32 * bank;
  153         func = pin >> 3;
  154         offset = ((pin & 0x07) << 2);
  155 
  156         data = A10_GPIO_READ(sc, A10_GPIO_GP_CFG(bank, func));
  157         data &= ~(7 << offset);
  158         data |= (f << offset);
  159         A10_GPIO_WRITE(sc, A10_GPIO_GP_CFG(bank, func), data);
  160 }
  161 
  162 static void
  163 a10_gpio_set_pud(struct a10_gpio_softc *sc, uint32_t pin, uint32_t state)
  164 {
  165         uint32_t bank, offset, pull, val;
  166 
  167         /* Must be called with lock held. */
  168         A10_GPIO_LOCK_ASSERT(sc);
  169 
  170         bank = pin / 32;
  171         pin = pin - 32 * bank;
  172         pull = pin >> 4;
  173         offset = ((pin & 0x0f) << 1);
  174 
  175         val = A10_GPIO_READ(sc, A10_GPIO_GP_PUL(bank, pull));
  176         val &= ~(0x03 << offset);
  177         val |= (state << offset);
  178         A10_GPIO_WRITE(sc, A10_GPIO_GP_PUL(bank, pull), val);
  179 }
  180 
  181 static void
  182 a10_gpio_pin_configure(struct a10_gpio_softc *sc, struct gpio_pin *pin,
  183     unsigned int flags)
  184 {
  185 
  186         A10_GPIO_LOCK(sc);
  187 
  188         /*
  189          * Manage input/output.
  190          */
  191         if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) {
  192                 pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT);
  193                 if (flags & GPIO_PIN_OUTPUT) {
  194                         pin->gp_flags |= GPIO_PIN_OUTPUT;
  195                         a10_gpio_set_function(sc, pin->gp_pin,
  196                             A10_GPIO_OUTPUT);
  197                 } else {
  198                         pin->gp_flags |= GPIO_PIN_INPUT;
  199                         a10_gpio_set_function(sc, pin->gp_pin,
  200                             A10_GPIO_INPUT);
  201                 }
  202         }
  203 
  204         /* Manage Pull-up/pull-down. */
  205         pin->gp_flags &= ~(GPIO_PIN_PULLUP|GPIO_PIN_PULLDOWN);
  206         if (flags & (GPIO_PIN_PULLUP|GPIO_PIN_PULLDOWN)) {
  207                 if (flags & GPIO_PIN_PULLUP) {
  208                         pin->gp_flags |= GPIO_PIN_PULLUP;
  209                         a10_gpio_set_pud(sc, pin->gp_pin, A10_GPIO_PULLUP);
  210                 } else {
  211                         pin->gp_flags |= GPIO_PIN_PULLDOWN;
  212                         a10_gpio_set_pud(sc, pin->gp_pin, A10_GPIO_PULLDOWN);
  213                 }
  214         } else 
  215                 a10_gpio_set_pud(sc, pin->gp_pin, A10_GPIO_NONE);
  216 
  217         A10_GPIO_UNLOCK(sc);
  218 }
  219 
  220 static int
  221 a10_gpio_pin_max(device_t dev, int *maxpin)
  222 {
  223 
  224         *maxpin = A10_GPIO_PINS - 1;
  225         return (0);
  226 }
  227 
  228 static int
  229 a10_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
  230 {
  231         struct a10_gpio_softc *sc = device_get_softc(dev);
  232         int i;
  233 
  234         for (i = 0; i < sc->sc_gpio_npins; i++) {
  235                 if (sc->sc_gpio_pins[i].gp_pin == pin)
  236                         break;
  237         }
  238 
  239         if (i >= sc->sc_gpio_npins)
  240                 return (EINVAL);
  241 
  242         A10_GPIO_LOCK(sc);
  243         *caps = sc->sc_gpio_pins[i].gp_caps;
  244         A10_GPIO_UNLOCK(sc);
  245 
  246         return (0);
  247 }
  248 
  249 static int
  250 a10_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
  251 {
  252         struct a10_gpio_softc *sc = device_get_softc(dev);
  253         int i;
  254 
  255         for (i = 0; i < sc->sc_gpio_npins; i++) {
  256                 if (sc->sc_gpio_pins[i].gp_pin == pin)
  257                         break;
  258         }
  259 
  260         if (i >= sc->sc_gpio_npins)
  261                 return (EINVAL);
  262 
  263         A10_GPIO_LOCK(sc);
  264         *flags = sc->sc_gpio_pins[i].gp_flags;
  265         A10_GPIO_UNLOCK(sc);
  266 
  267         return (0);
  268 }
  269 
  270 static int
  271 a10_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
  272 {
  273         struct a10_gpio_softc *sc = device_get_softc(dev);
  274         int i;
  275 
  276         for (i = 0; i < sc->sc_gpio_npins; i++) {
  277                 if (sc->sc_gpio_pins[i].gp_pin == pin)
  278                         break;
  279         }
  280 
  281         if (i >= sc->sc_gpio_npins)
  282                 return (EINVAL);
  283 
  284         A10_GPIO_LOCK(sc);
  285         memcpy(name, sc->sc_gpio_pins[i].gp_name, GPIOMAXNAME);
  286         A10_GPIO_UNLOCK(sc);
  287 
  288         return (0);
  289 }
  290 
  291 static int
  292 a10_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
  293 {
  294         struct a10_gpio_softc *sc = device_get_softc(dev);
  295         int i;
  296 
  297         for (i = 0; i < sc->sc_gpio_npins; i++) {
  298                 if (sc->sc_gpio_pins[i].gp_pin == pin)
  299                         break;
  300         }
  301 
  302         if (i >= sc->sc_gpio_npins)
  303                 return (EINVAL);
  304 
  305         a10_gpio_pin_configure(sc, &sc->sc_gpio_pins[i], flags);
  306 
  307         return (0);
  308 }
  309 
  310 static int
  311 a10_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
  312 {
  313         struct a10_gpio_softc *sc = device_get_softc(dev);
  314         uint32_t bank, offset, data;
  315         int i;
  316 
  317         for (i = 0; i < sc->sc_gpio_npins; i++) {
  318                 if (sc->sc_gpio_pins[i].gp_pin == pin)
  319                         break;
  320         }
  321 
  322         if (i >= sc->sc_gpio_npins)
  323                 return (EINVAL);
  324 
  325         bank = pin / 32;
  326         pin = pin - 32 * bank;
  327         offset = pin & 0x1f;
  328 
  329         A10_GPIO_LOCK(sc);
  330         data = A10_GPIO_READ(sc, A10_GPIO_GP_DAT(bank));
  331         if (value)
  332                 data |= (1 << offset);
  333         else
  334                 data &= ~(1 << offset);
  335         A10_GPIO_WRITE(sc, A10_GPIO_GP_DAT(bank), data);
  336         A10_GPIO_UNLOCK(sc);
  337 
  338         return (0);
  339 }
  340 
  341 static int
  342 a10_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
  343 {
  344         struct a10_gpio_softc *sc = device_get_softc(dev);
  345         uint32_t bank, offset, reg_data;
  346         int i;
  347 
  348         for (i = 0; i < sc->sc_gpio_npins; i++) {
  349                 if (sc->sc_gpio_pins[i].gp_pin == pin)
  350                         break;
  351         }
  352 
  353         if (i >= sc->sc_gpio_npins)
  354                 return (EINVAL);
  355 
  356         bank = pin / 32;
  357         pin = pin - 32 * bank;
  358         offset = pin & 0x1f;
  359 
  360         A10_GPIO_LOCK(sc);
  361         reg_data = A10_GPIO_READ(sc, A10_GPIO_GP_DAT(bank));
  362         A10_GPIO_UNLOCK(sc);
  363         *val = (reg_data & (1 << offset)) ? 1 : 0;
  364 
  365         return (0);
  366 }
  367 
  368 static int
  369 a10_gpio_pin_toggle(device_t dev, uint32_t pin)
  370 {
  371         struct a10_gpio_softc *sc = device_get_softc(dev);
  372         uint32_t bank, data, offset;
  373         int i;
  374 
  375         for (i = 0; i < sc->sc_gpio_npins; i++) {
  376                 if (sc->sc_gpio_pins[i].gp_pin == pin)
  377                         break;
  378         }
  379 
  380         if (i >= sc->sc_gpio_npins)
  381                 return (EINVAL);
  382 
  383         bank = pin / 32;
  384         pin = pin - 32 * bank;
  385         offset = pin & 0x1f;
  386 
  387         A10_GPIO_LOCK(sc);
  388         data = A10_GPIO_READ(sc, A10_GPIO_GP_DAT(bank));
  389         if (data & (1 << offset))
  390                 data &= ~(1 << offset);
  391         else
  392                 data |= (1 << offset);
  393         A10_GPIO_WRITE(sc, A10_GPIO_GP_DAT(bank), data);
  394         A10_GPIO_UNLOCK(sc);
  395 
  396         return (0);
  397 }
  398 
  399 static int
  400 a10_gpio_probe(device_t dev)
  401 {
  402 
  403         if (!ofw_bus_status_okay(dev))
  404                 return (ENXIO);
  405 
  406         if (!ofw_bus_is_compatible(dev, "allwinner,sun4i-gpio"))
  407                 return (ENXIO);
  408 
  409         device_set_desc(dev, "Allwinner GPIO controller");
  410         return (BUS_PROBE_DEFAULT);
  411 }
  412 
  413 static int
  414 a10_gpio_attach(device_t dev)
  415 {
  416         struct a10_gpio_softc *sc = device_get_softc(dev);
  417         uint32_t func;
  418         int i, rid;
  419         phandle_t gpio;
  420 
  421         sc->sc_dev = dev;
  422 
  423         mtx_init(&sc->sc_mtx, "a10 gpio", "gpio", MTX_DEF);
  424 
  425         rid = 0;
  426         sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
  427             RF_ACTIVE);
  428         if (!sc->sc_mem_res) {
  429                 device_printf(dev, "cannot allocate memory window\n");
  430                 return (ENXIO);
  431         }
  432 
  433         sc->sc_bst = rman_get_bustag(sc->sc_mem_res);
  434         sc->sc_bsh = rman_get_bushandle(sc->sc_mem_res);
  435 
  436         rid = 0;
  437         sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
  438             RF_ACTIVE);
  439         if (!sc->sc_irq_res) {
  440                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
  441                 device_printf(dev, "cannot allocate interrupt\n");
  442                 return (ENXIO);
  443         }
  444 
  445         /* Find our node. */
  446         gpio = ofw_bus_get_node(sc->sc_dev);
  447 
  448         if (!OF_hasprop(gpio, "gpio-controller"))
  449                 /* Node is not a GPIO controller. */
  450                 goto fail;
  451 
  452         /* Initialize the software controlled pins. */
  453         for (i = 0; i < A10_GPIO_PINS; i++) {
  454                 snprintf(sc->sc_gpio_pins[i].gp_name, GPIOMAXNAME,
  455                     "pin %d", i);
  456                 func = a10_gpio_get_function(sc, i);
  457                 sc->sc_gpio_pins[i].gp_pin = i;
  458                 sc->sc_gpio_pins[i].gp_caps = A10_GPIO_DEFAULT_CAPS;
  459                 sc->sc_gpio_pins[i].gp_flags = a10_gpio_func_flag(func);
  460         }
  461         sc->sc_gpio_npins = i;
  462 
  463         device_add_child(dev, "gpioc", -1);
  464         device_add_child(dev, "gpiobus", -1);
  465 
  466         a10_gpio_sc = sc;
  467 
  468         return (bus_generic_attach(dev));
  469 
  470 fail:
  471         if (sc->sc_irq_res)
  472                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res);
  473         if (sc->sc_mem_res)
  474                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
  475         return (ENXIO);
  476 }
  477 
  478 static int
  479 a10_gpio_detach(device_t dev)
  480 {
  481 
  482         return (EBUSY);
  483 }
  484 
  485 static device_method_t a10_gpio_methods[] = {
  486         /* Device interface */
  487         DEVMETHOD(device_probe,         a10_gpio_probe),
  488         DEVMETHOD(device_attach,        a10_gpio_attach),
  489         DEVMETHOD(device_detach,        a10_gpio_detach),
  490 
  491         /* GPIO protocol */
  492         DEVMETHOD(gpio_pin_max,         a10_gpio_pin_max),
  493         DEVMETHOD(gpio_pin_getname,     a10_gpio_pin_getname),
  494         DEVMETHOD(gpio_pin_getflags,    a10_gpio_pin_getflags),
  495         DEVMETHOD(gpio_pin_getcaps,     a10_gpio_pin_getcaps),
  496         DEVMETHOD(gpio_pin_setflags,    a10_gpio_pin_setflags),
  497         DEVMETHOD(gpio_pin_get,         a10_gpio_pin_get),
  498         DEVMETHOD(gpio_pin_set,         a10_gpio_pin_set),
  499         DEVMETHOD(gpio_pin_toggle,      a10_gpio_pin_toggle),
  500 
  501         DEVMETHOD_END
  502 };
  503 
  504 static devclass_t a10_gpio_devclass;
  505 
  506 static driver_t a10_gpio_driver = {
  507         "gpio",
  508         a10_gpio_methods,
  509         sizeof(struct a10_gpio_softc),
  510 };
  511 
  512 DRIVER_MODULE(a10_gpio, simplebus, a10_gpio_driver, a10_gpio_devclass, 0, 0);
  513 
  514 int
  515 a10_emac_gpio_config(uint32_t pin)
  516 {
  517         struct a10_gpio_softc *sc = a10_gpio_sc;
  518 
  519         if (sc == NULL)
  520                 return (ENXIO);
  521 
  522         /* Configure pin mux settings for MII. */
  523         A10_GPIO_LOCK(sc);
  524         a10_gpio_set_function(sc, pin, A10_GPIO_PULLDOWN);
  525         A10_GPIO_UNLOCK(sc);
  526 
  527         return (0);
  528 }

Cache object: 146397761ba1cddb70fa42558b84780c


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