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@gmail.com>
    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.0/sys/arm/allwinner/a10_gpio.c 249449 2013-04-13 21:21:13Z dim $");
   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/frame.h>
   49 #include <machine/intr.h>
   50 
   51 #include <dev/fdt/fdt_common.h>
   52 #include <dev/ofw/ofw_bus.h>
   53 #include <dev/ofw/ofw_bus_subr.h>
   54 
   55 #include "gpio_if.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 #define A10_GPIO_WRITE(_sc, _off, _val)         \
  107     bus_space_write_4(_sc->sc_bst, _sc->sc_bsh, _off, _val)
  108 #define A10_GPIO_READ(_sc, _off)                \
  109     bus_space_read_4(_sc->sc_bst, _sc->sc_bsh, _off)
  110 
  111 static uint32_t
  112 a10_gpio_get_function(struct a10_gpio_softc *sc, uint32_t pin)
  113 {
  114         uint32_t bank, func, offset;
  115 
  116         bank = pin / 32;
  117         pin = pin - 32 * bank;
  118         func = pin >> 3;
  119         offset = ((pin & 0x07) << 2);
  120 
  121         A10_GPIO_LOCK(sc);
  122         func = (A10_GPIO_READ(sc, A10_GPIO_GP_CFG(bank, func)) >> offset) & 7;
  123         A10_GPIO_UNLOCK(sc);
  124 
  125         return (func);
  126 }
  127 
  128 static uint32_t
  129 a10_gpio_func_flag(uint32_t nfunc)
  130 {
  131 
  132         switch (nfunc) {
  133         case A10_GPIO_INPUT:
  134                 return (GPIO_PIN_INPUT);
  135         case A10_GPIO_OUTPUT:
  136                 return (GPIO_PIN_OUTPUT);
  137         }
  138         return (0);
  139 }
  140 
  141 static void
  142 a10_gpio_set_function(struct a10_gpio_softc *sc, uint32_t pin, uint32_t f)
  143 {
  144         uint32_t bank, func, data, offset;
  145 
  146         /* Must be called with lock held. */
  147         A10_GPIO_LOCK_ASSERT(sc);
  148 
  149         bank = pin / 32;
  150         pin = pin - 32 * bank;
  151         func = pin >> 3;
  152         offset = ((pin & 0x07) << 2);
  153 
  154         data = A10_GPIO_READ(sc, A10_GPIO_GP_CFG(bank, func));
  155         data &= ~(7 << offset);
  156         data |= (f << offset);
  157         A10_GPIO_WRITE(sc, A10_GPIO_GP_CFG(bank, func), data);
  158 }
  159 
  160 static void
  161 a10_gpio_set_pud(struct a10_gpio_softc *sc, uint32_t pin, uint32_t state)
  162 {
  163         uint32_t bank, offset, pull, val;
  164 
  165         /* Must be called with lock held. */
  166         A10_GPIO_LOCK_ASSERT(sc);
  167 
  168         bank = pin / 32;
  169         pin = pin - 32 * bank;
  170         pull = pin >> 4;
  171         offset = ((pin & 0x0f) << 1);
  172 
  173         val = A10_GPIO_READ(sc, A10_GPIO_GP_PUL(bank, pull));
  174         val &= ~(0x03 << offset);
  175         val |= (state << offset);
  176         A10_GPIO_WRITE(sc, A10_GPIO_GP_PUL(bank, pull), val);
  177 }
  178 
  179 static void
  180 a10_gpio_pin_configure(struct a10_gpio_softc *sc, struct gpio_pin *pin,
  181     unsigned int flags)
  182 {
  183 
  184         A10_GPIO_LOCK(sc);
  185 
  186         /*
  187          * Manage input/output.
  188          */
  189         if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) {
  190                 pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT);
  191                 if (flags & GPIO_PIN_OUTPUT) {
  192                         pin->gp_flags |= GPIO_PIN_OUTPUT;
  193                         a10_gpio_set_function(sc, pin->gp_pin,
  194                             A10_GPIO_OUTPUT);
  195                 } else {
  196                         pin->gp_flags |= GPIO_PIN_INPUT;
  197                         a10_gpio_set_function(sc, pin->gp_pin,
  198                             A10_GPIO_INPUT);
  199                 }
  200         }
  201 
  202         /* Manage Pull-up/pull-down. */
  203         pin->gp_flags &= ~(GPIO_PIN_PULLUP|GPIO_PIN_PULLDOWN);
  204         if (flags & (GPIO_PIN_PULLUP|GPIO_PIN_PULLDOWN)) {
  205                 if (flags & GPIO_PIN_PULLUP) {
  206                         pin->gp_flags |= GPIO_PIN_PULLUP;
  207                         a10_gpio_set_pud(sc, pin->gp_pin, A10_GPIO_PULLUP);
  208                 } else {
  209                         pin->gp_flags |= GPIO_PIN_PULLDOWN;
  210                         a10_gpio_set_pud(sc, pin->gp_pin, A10_GPIO_PULLDOWN);
  211                 }
  212         } else 
  213                 a10_gpio_set_pud(sc, pin->gp_pin, A10_GPIO_NONE);
  214 
  215         A10_GPIO_UNLOCK(sc);
  216 }
  217 
  218 static int
  219 a10_gpio_pin_max(device_t dev, int *maxpin)
  220 {
  221 
  222         *maxpin = A10_GPIO_PINS - 1;
  223         return (0);
  224 }
  225 
  226 static int
  227 a10_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
  228 {
  229         struct a10_gpio_softc *sc = device_get_softc(dev);
  230         int i;
  231 
  232         for (i = 0; i < sc->sc_gpio_npins; i++) {
  233                 if (sc->sc_gpio_pins[i].gp_pin == pin)
  234                         break;
  235         }
  236 
  237         if (i >= sc->sc_gpio_npins)
  238                 return (EINVAL);
  239 
  240         A10_GPIO_LOCK(sc);
  241         *caps = sc->sc_gpio_pins[i].gp_caps;
  242         A10_GPIO_UNLOCK(sc);
  243 
  244         return (0);
  245 }
  246 
  247 static int
  248 a10_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
  249 {
  250         struct a10_gpio_softc *sc = device_get_softc(dev);
  251         int i;
  252 
  253         for (i = 0; i < sc->sc_gpio_npins; i++) {
  254                 if (sc->sc_gpio_pins[i].gp_pin == pin)
  255                         break;
  256         }
  257 
  258         if (i >= sc->sc_gpio_npins)
  259                 return (EINVAL);
  260 
  261         A10_GPIO_LOCK(sc);
  262         *flags = sc->sc_gpio_pins[i].gp_flags;
  263         A10_GPIO_UNLOCK(sc);
  264 
  265         return (0);
  266 }
  267 
  268 static int
  269 a10_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
  270 {
  271         struct a10_gpio_softc *sc = device_get_softc(dev);
  272         int i;
  273 
  274         for (i = 0; i < sc->sc_gpio_npins; i++) {
  275                 if (sc->sc_gpio_pins[i].gp_pin == pin)
  276                         break;
  277         }
  278 
  279         if (i >= sc->sc_gpio_npins)
  280                 return (EINVAL);
  281 
  282         A10_GPIO_LOCK(sc);
  283         memcpy(name, sc->sc_gpio_pins[i].gp_name, GPIOMAXNAME);
  284         A10_GPIO_UNLOCK(sc);
  285 
  286         return (0);
  287 }
  288 
  289 static int
  290 a10_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
  291 {
  292         struct a10_gpio_softc *sc = device_get_softc(dev);
  293         int i;
  294 
  295         for (i = 0; i < sc->sc_gpio_npins; i++) {
  296                 if (sc->sc_gpio_pins[i].gp_pin == pin)
  297                         break;
  298         }
  299 
  300         if (i >= sc->sc_gpio_npins)
  301                 return (EINVAL);
  302 
  303         /* Check for unwanted flags. */
  304         if ((flags & sc->sc_gpio_pins[i].gp_caps) != flags)
  305                 return (EINVAL);
  306 
  307         /* Can't mix input/output together. */
  308         if ((flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) ==
  309             (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT))
  310                 return (EINVAL);
  311 
  312         /* Can't mix pull-up/pull-down together. */
  313         if ((flags & (GPIO_PIN_PULLUP|GPIO_PIN_PULLDOWN)) ==
  314             (GPIO_PIN_PULLUP|GPIO_PIN_PULLDOWN))
  315                 return (EINVAL);
  316 
  317         a10_gpio_pin_configure(sc, &sc->sc_gpio_pins[i], flags);
  318 
  319         return (0);
  320 }
  321 
  322 static int
  323 a10_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
  324 {
  325         struct a10_gpio_softc *sc = device_get_softc(dev);
  326         uint32_t bank, offset, data;
  327         int i;
  328 
  329         for (i = 0; i < sc->sc_gpio_npins; i++) {
  330                 if (sc->sc_gpio_pins[i].gp_pin == pin)
  331                         break;
  332         }
  333 
  334         if (i >= sc->sc_gpio_npins)
  335                 return (EINVAL);
  336 
  337         bank = pin / 32;
  338         pin = pin - 32 * bank;
  339         offset = pin & 0x1f;
  340 
  341         A10_GPIO_LOCK(sc);
  342         data = A10_GPIO_READ(sc, A10_GPIO_GP_DAT(bank));
  343         if (value)
  344                 data |= (1 << offset);
  345         else
  346                 data &= ~(1 << offset);
  347         A10_GPIO_WRITE(sc, A10_GPIO_GP_DAT(bank), data);
  348         A10_GPIO_UNLOCK(sc);
  349 
  350         return (0);
  351 }
  352 
  353 static int
  354 a10_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
  355 {
  356         struct a10_gpio_softc *sc = device_get_softc(dev);
  357         uint32_t bank, offset, reg_data;
  358         int i;
  359 
  360         for (i = 0; i < sc->sc_gpio_npins; i++) {
  361                 if (sc->sc_gpio_pins[i].gp_pin == pin)
  362                         break;
  363         }
  364 
  365         if (i >= sc->sc_gpio_npins)
  366                 return (EINVAL);
  367 
  368         bank = pin / 32;
  369         pin = pin - 32 * bank;
  370         offset = pin & 0x1f;
  371 
  372         A10_GPIO_LOCK(sc);
  373         reg_data = A10_GPIO_READ(sc, A10_GPIO_GP_DAT(bank));
  374         A10_GPIO_UNLOCK(sc);
  375         *val = (reg_data & (1 << offset)) ? 1 : 0;
  376 
  377         return (0);
  378 }
  379 
  380 static int
  381 a10_gpio_pin_toggle(device_t dev, uint32_t pin)
  382 {
  383         struct a10_gpio_softc *sc = device_get_softc(dev);
  384         uint32_t bank, data, offset;
  385         int i;
  386 
  387         for (i = 0; i < sc->sc_gpio_npins; i++) {
  388                 if (sc->sc_gpio_pins[i].gp_pin == pin)
  389                         break;
  390         }
  391 
  392         if (i >= sc->sc_gpio_npins)
  393                 return (EINVAL);
  394 
  395         bank = pin / 32;
  396         pin = pin - 32 * bank;
  397         offset = pin & 0x1f;
  398 
  399         A10_GPIO_LOCK(sc);
  400         data = A10_GPIO_READ(sc, A10_GPIO_GP_DAT(bank));
  401         if (data & (1 << offset))
  402                 data &= ~(1 << offset);
  403         else
  404                 data |= (1 << offset);
  405         A10_GPIO_WRITE(sc, A10_GPIO_GP_DAT(bank), data);
  406         A10_GPIO_UNLOCK(sc);
  407 
  408         return (0);
  409 }
  410 
  411 static int
  412 a10_gpio_probe(device_t dev)
  413 {
  414         if (!ofw_bus_is_compatible(dev, "allwinner,sun4i-gpio"))
  415                 return (ENXIO);
  416 
  417         device_set_desc(dev, "Allwinner GPIO controller");
  418         return (BUS_PROBE_DEFAULT);
  419 }
  420 
  421 static int
  422 a10_gpio_attach(device_t dev)
  423 {
  424         struct a10_gpio_softc *sc = device_get_softc(dev);
  425         uint32_t func;
  426         int i, rid;
  427         phandle_t gpio;
  428 
  429         sc->sc_dev = dev;
  430 
  431         mtx_init(&sc->sc_mtx, "a10 gpio", "gpio", MTX_DEF);
  432 
  433         rid = 0;
  434         sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
  435             RF_ACTIVE);
  436         if (!sc->sc_mem_res) {
  437                 device_printf(dev, "cannot allocate memory window\n");
  438                 return (ENXIO);
  439         }
  440 
  441         sc->sc_bst = rman_get_bustag(sc->sc_mem_res);
  442         sc->sc_bsh = rman_get_bushandle(sc->sc_mem_res);
  443 
  444         rid = 0;
  445         sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
  446             RF_ACTIVE);
  447         if (!sc->sc_irq_res) {
  448                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
  449                 device_printf(dev, "cannot allocate interrupt\n");
  450                 return (ENXIO);
  451         }
  452 
  453         /* Find our node. */
  454         gpio = ofw_bus_get_node(sc->sc_dev);
  455 
  456         if (!OF_hasprop(gpio, "gpio-controller"))
  457                 /* Node is not a GPIO controller. */
  458                 goto fail;
  459 
  460         /* Initialize the software controlled pins. */
  461         for (i = 0; i < A10_GPIO_PINS; i++) {
  462                 snprintf(sc->sc_gpio_pins[i].gp_name, GPIOMAXNAME,
  463                     "pin %d", i);
  464                 func = a10_gpio_get_function(sc, i);
  465                 sc->sc_gpio_pins[i].gp_pin = i;
  466                 sc->sc_gpio_pins[i].gp_caps = A10_GPIO_DEFAULT_CAPS;
  467                 sc->sc_gpio_pins[i].gp_flags = a10_gpio_func_flag(func);
  468         }
  469         sc->sc_gpio_npins = i;
  470 
  471         device_add_child(dev, "gpioc", device_get_unit(dev));
  472         device_add_child(dev, "gpiobus", device_get_unit(dev));
  473         return (bus_generic_attach(dev));
  474 
  475 fail:
  476         if (sc->sc_irq_res)
  477                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res);
  478         if (sc->sc_mem_res)
  479                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
  480         return (ENXIO);
  481 }
  482 
  483 static int
  484 a10_gpio_detach(device_t dev)
  485 {
  486 
  487         return (EBUSY);
  488 }
  489 
  490 static device_method_t a10_gpio_methods[] = {
  491         /* Device interface */
  492         DEVMETHOD(device_probe,         a10_gpio_probe),
  493         DEVMETHOD(device_attach,        a10_gpio_attach),
  494         DEVMETHOD(device_detach,        a10_gpio_detach),
  495 
  496         /* GPIO protocol */
  497         DEVMETHOD(gpio_pin_max,         a10_gpio_pin_max),
  498         DEVMETHOD(gpio_pin_getname,     a10_gpio_pin_getname),
  499         DEVMETHOD(gpio_pin_getflags,    a10_gpio_pin_getflags),
  500         DEVMETHOD(gpio_pin_getcaps,     a10_gpio_pin_getcaps),
  501         DEVMETHOD(gpio_pin_setflags,    a10_gpio_pin_setflags),
  502         DEVMETHOD(gpio_pin_get,         a10_gpio_pin_get),
  503         DEVMETHOD(gpio_pin_set,         a10_gpio_pin_set),
  504         DEVMETHOD(gpio_pin_toggle,      a10_gpio_pin_toggle),
  505 
  506         DEVMETHOD_END
  507 };
  508 
  509 static devclass_t a10_gpio_devclass;
  510 
  511 static driver_t a10_gpio_driver = {
  512         "gpio",
  513         a10_gpio_methods,
  514         sizeof(struct a10_gpio_softc),
  515 };
  516 
  517 DRIVER_MODULE(a10_gpio, simplebus, a10_gpio_driver, a10_gpio_devclass, 0, 0);

Cache object: 94c5c6742c9c0e9d09535a057b0a8bf3


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