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/mv/mvebu_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 Michal Meloun <mmel@FreeBSD.org>
    3  *
    4  * Redistribution and use in source and binary forms, with or without
    5  * modification, are permitted provided that the following conditions
    6  * are met:
    7  * 1. Redistributions of source code must retain the above copyright
    8  *    notice, this list of conditions and the following disclaimer.
    9  * 2. Redistributions in binary form must reproduce the above copyright
   10  *    notice, this list of conditions and the following disclaimer in the
   11  *    documentation and/or other materials provided with the distribution.
   12  *
   13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   23  * SUCH DAMAGE.
   24  */
   25 
   26 #include <sys/cdefs.h>
   27 __FBSDID("$FreeBSD$");
   28 
   29 /*
   30  * ARMADA 8040 GPIO driver.
   31  */
   32 #include "opt_platform.h"
   33 #include <sys/param.h>
   34 #include <sys/systm.h>
   35 #include <sys/bus.h>
   36 #include <sys/gpio.h>
   37 #include <sys/kernel.h>
   38 #include <sys/proc.h>
   39 #include <sys/rman.h>
   40 #include <sys/lock.h>
   41 #include <sys/module.h>
   42 #include <sys/mutex.h>
   43 
   44 #include <machine/bus.h>
   45 #include <machine/intr.h>
   46 #include <machine/resource.h>
   47 
   48 #include <dev/extres/syscon/syscon.h>
   49 
   50 #include <dev/gpio/gpiobusvar.h>
   51 
   52 #include <dev/ofw/openfirm.h>
   53 #include <dev/ofw/ofw_bus.h>
   54 #include <dev/ofw/ofw_bus_subr.h>
   55 
   56 #include "pic_if.h"
   57 #include "syscon_if.h"
   58 
   59 #define GPIO_LOCK(_sc)          mtx_lock(&(_sc)->mtx)
   60 #define GPIO_UNLOCK(_sc)        mtx_unlock(&(_sc)->mtx)
   61 #define GPIO_LOCK_INIT(_sc)     mtx_init(&_sc->mtx,                     \
   62             device_get_nameunit(_sc->dev), "mvebu_gpio", MTX_DEF)
   63 #define GPIO_LOCK_DESTROY(_sc)  mtx_destroy(&_sc->mtx);
   64 #define GPIO_ASSERT_LOCKED(_sc) mtx_assert(&_sc->mtx, MA_OWNED);
   65 #define GPIO_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->mtx, MA_NOTOWNED);
   66 
   67 #define GPIO_DATA_OUT           0x00
   68 #define GPIO_CONTROL            0x04
   69 #define GPIO_BLINK_ENA          0x08
   70 #define GPIO_DATA_IN_POL        0x0C
   71 #define GPIO_DATA_IN            0x10
   72 #define GPIO_INT_CAUSE          0x14
   73 #define GPIO_INT_MASK           0x18
   74 #define GPIO_INT_LEVEL_MASK     0x1C
   75 #define GPIO_CONTROL_SET        0x28
   76 #define GPIO_CONTROL_CLR        0x2C
   77 #define GPIO_DATA_SET           0x30
   78 #define GPIO_DATA_CLR           0x34
   79 
   80 #define GPIO_BIT(_p)            ((_p) % 32)
   81 #define GPIO_REGNUM(_p)         ((_p) / 32)
   82 
   83 #define MV_GPIO_MAX_NIRQS       4
   84 #define MV_GPIO_MAX_NPINS       32
   85 
   86 #define RD4(sc, reg)            SYSCON_READ_4((sc)->syscon, (reg))
   87 #define WR4(sc, reg, val)       SYSCON_WRITE_4((sc)->syscon, (reg), (val))
   88 
   89 struct mvebu_gpio_irqsrc {
   90         struct intr_irqsrc      isrc;
   91         u_int                   irq;
   92         bool                    is_level;
   93         bool                    is_inverted;
   94 };
   95 
   96 struct mvebu_gpio_softc;
   97 struct mvebu_gpio_irq_cookie {
   98         struct mvebu_gpio_softc *sc;
   99         int                     bank_num;
  100 };
  101 
  102 struct mvebu_gpio_softc {
  103         device_t                dev;
  104         device_t                busdev;
  105         struct mtx              mtx;
  106         struct syscon           *syscon;
  107         uint32_t                offset;
  108         struct resource         *irq_res[MV_GPIO_MAX_NIRQS];
  109         void                    *irq_ih[MV_GPIO_MAX_NIRQS];
  110         struct mvebu_gpio_irq_cookie irq_cookies[MV_GPIO_MAX_NIRQS];
  111         int                     gpio_npins;
  112         struct gpio_pin         gpio_pins[MV_GPIO_MAX_NPINS];
  113         struct mvebu_gpio_irqsrc *isrcs;
  114 };
  115 
  116 static struct ofw_compat_data compat_data[] = {
  117         {"marvell,armada-8k-gpio", 1},
  118         {NULL, 0}
  119 };
  120 
  121 /* --------------------------------------------------------------------------
  122  *
  123  * GPIO
  124  *
  125  */
  126 static inline void
  127 gpio_write(struct mvebu_gpio_softc *sc, bus_size_t reg,
  128     struct gpio_pin *pin, uint32_t val)
  129 {
  130         uint32_t tmp;
  131         int bit;
  132 
  133         bit = GPIO_BIT(pin->gp_pin);
  134         tmp = 0x100 << bit;             /* mask */
  135         tmp |= (val & 1) << bit;        /* value */
  136         SYSCON_WRITE_4(sc->syscon, sc->offset + GPIO_REGNUM(pin->gp_pin) + reg,
  137             tmp);
  138 }
  139 
  140 static inline uint32_t
  141 gpio_read(struct mvebu_gpio_softc *sc, bus_size_t reg, struct gpio_pin *pin)
  142 {
  143         int bit;
  144         uint32_t val;
  145 
  146         bit = GPIO_BIT(pin->gp_pin);
  147         val = SYSCON_READ_4(sc->syscon,
  148             sc->offset + GPIO_REGNUM(pin->gp_pin) + reg);
  149         return (val >> bit) & 1;
  150 }
  151 
  152 static void
  153 mvebu_gpio_pin_configure(struct mvebu_gpio_softc *sc, struct gpio_pin *pin,
  154     unsigned int flags)
  155 {
  156 
  157         if ((flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) == 0)
  158                 return;
  159 
  160         /* Manage input/output */
  161         pin->gp_flags &= ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT);
  162         if (flags & GPIO_PIN_OUTPUT) {
  163                 pin->gp_flags |= GPIO_PIN_OUTPUT;
  164                 gpio_write(sc, GPIO_CONTROL_SET, pin, 1);
  165         } else {
  166                 pin->gp_flags |= GPIO_PIN_INPUT;
  167                 gpio_write(sc, GPIO_CONTROL_CLR, pin, 1);
  168         }
  169 }
  170 
  171 static device_t
  172 mvebu_gpio_get_bus(device_t dev)
  173 {
  174         struct mvebu_gpio_softc *sc;
  175 
  176         sc = device_get_softc(dev);
  177         return (sc->busdev);
  178 }
  179 
  180 static int
  181 mvebu_gpio_pin_max(device_t dev, int *maxpin)
  182 {
  183         struct mvebu_gpio_softc *sc;
  184 
  185         sc = device_get_softc(dev);
  186         *maxpin = sc->gpio_npins - 1;
  187         return (0);
  188 }
  189 
  190 static int
  191 mvebu_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
  192 {
  193         struct mvebu_gpio_softc *sc;
  194 
  195         sc = device_get_softc(dev);
  196         if (pin >= sc->gpio_npins)
  197                 return (EINVAL);
  198 
  199         *caps = sc->gpio_pins[pin].gp_caps;
  200 
  201         return (0);
  202 }
  203 
  204 static int
  205 mvebu_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
  206 {
  207         struct mvebu_gpio_softc *sc;
  208 
  209         sc = device_get_softc(dev);
  210         if (pin >= sc->gpio_npins)
  211                 return (EINVAL);
  212 
  213         *flags = sc->gpio_pins[pin].gp_flags;
  214 
  215         return (0);
  216 }
  217 
  218 static int
  219 mvebu_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
  220 {
  221         struct mvebu_gpio_softc *sc;
  222 
  223         sc = device_get_softc(dev);
  224         if (pin >= sc->gpio_npins)
  225                 return (EINVAL);
  226 
  227         memcpy(name, sc->gpio_pins[pin].gp_name, GPIOMAXNAME);
  228 
  229         return (0);
  230 }
  231 
  232 static int
  233 mvebu_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
  234 {
  235         struct mvebu_gpio_softc *sc;
  236 
  237         sc = device_get_softc(dev);
  238         if (pin >= sc->gpio_npins)
  239                 return (EINVAL);
  240 
  241         mvebu_gpio_pin_configure(sc, &sc->gpio_pins[pin], flags);
  242 
  243         return (0);
  244 }
  245 
  246 static int
  247 mvebu_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
  248 {
  249         struct mvebu_gpio_softc *sc;
  250 
  251         sc = device_get_softc(dev);
  252         if (pin >= sc->gpio_npins)
  253                 return (EINVAL);
  254 
  255         if (value != 0)
  256                 gpio_write(sc, GPIO_DATA_SET, &sc->gpio_pins[pin], 1);
  257         else
  258                 gpio_write(sc, GPIO_DATA_CLR, &sc->gpio_pins[pin], 1);
  259 
  260         return (0);
  261 }
  262 
  263 static int
  264 mvebu_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
  265 {
  266         struct mvebu_gpio_softc *sc;
  267 
  268         sc = device_get_softc(dev);
  269         if (pin >= sc->gpio_npins)
  270                 return (EINVAL);
  271 
  272         GPIO_LOCK(sc);
  273         *val = gpio_read(sc, GPIO_DATA_IN, &sc->gpio_pins[pin]);
  274         *val ^= gpio_read(sc, GPIO_DATA_IN_POL, &sc->gpio_pins[pin]);
  275         GPIO_UNLOCK(sc);
  276 
  277         return (0);
  278 }
  279 
  280 static int
  281 mvebu_gpio_pin_toggle(device_t dev, uint32_t pin)
  282 {
  283         struct mvebu_gpio_softc *sc;
  284         uint32_t val;
  285 
  286         sc = device_get_softc(dev);
  287         if (pin >= sc->gpio_npins)
  288                 return (EINVAL);
  289 
  290         GPIO_LOCK(sc);
  291         mvebu_gpio_pin_get(sc->dev, pin, &val);
  292         if (val != 0)
  293                 gpio_write(sc, GPIO_DATA_CLR, &sc->gpio_pins[pin], 1);
  294         else
  295                 gpio_write(sc, GPIO_DATA_SET, &sc->gpio_pins[pin], 1);
  296         GPIO_UNLOCK(sc);
  297 
  298         return (0);
  299 }
  300 
  301 /* --------------------------------------------------------------------------
  302  *
  303  * Interrupts
  304  *
  305  */
  306 static inline void
  307 intr_modify(struct mvebu_gpio_softc *sc, bus_addr_t reg,
  308     struct mvebu_gpio_irqsrc *mgi, uint32_t val, uint32_t mask)
  309 {
  310         int bit;
  311 
  312         bit = GPIO_BIT(mgi->irq);
  313         GPIO_LOCK(sc);
  314         val = SYSCON_MODIFY_4(sc->syscon,
  315             sc->offset + GPIO_REGNUM(mgi->irq) + reg, val, mask);
  316         GPIO_UNLOCK(sc);
  317 }
  318 
  319 static inline void
  320 mvebu_gpio_isrc_mask(struct mvebu_gpio_softc *sc,
  321      struct mvebu_gpio_irqsrc *mgi, uint32_t val)
  322 {
  323 
  324         if (mgi->is_level)
  325                 intr_modify(sc, GPIO_INT_LEVEL_MASK, mgi, val, 1);
  326         else
  327                 intr_modify(sc, GPIO_INT_MASK, mgi, val, 1);
  328 }
  329 
  330 static inline void
  331 mvebu_gpio_isrc_eoi(struct mvebu_gpio_softc *sc,
  332      struct mvebu_gpio_irqsrc *mgi)
  333 {
  334 
  335         if (!mgi->is_level)
  336                 intr_modify(sc, GPIO_INT_CAUSE, mgi, 1, 1);
  337 }
  338 
  339 static int
  340 mvebu_gpio_pic_attach(struct mvebu_gpio_softc *sc)
  341 {
  342         int rv;
  343         uint32_t irq;
  344         const char *name;
  345 
  346         sc->isrcs = malloc(sizeof(*sc->isrcs) * sc->gpio_npins, M_DEVBUF,
  347             M_WAITOK | M_ZERO);
  348 
  349         name = device_get_nameunit(sc->dev);
  350         for (irq = 0; irq < sc->gpio_npins; irq++) {
  351                 sc->isrcs[irq].irq = irq;
  352                 sc->isrcs[irq].is_level = false;
  353                 sc->isrcs[irq].is_inverted = false;
  354                 rv = intr_isrc_register(&sc->isrcs[irq].isrc,
  355                     sc->dev, 0, "%s,%u", name, irq);
  356                 if (rv != 0)
  357                         return (rv); /* XXX deregister ISRCs */
  358         }
  359         if (intr_pic_register(sc->dev,
  360             OF_xref_from_node(ofw_bus_get_node(sc->dev))) == NULL)
  361                 return (ENXIO);
  362 
  363         return (0);
  364 }
  365 
  366 static int
  367 mvebu_gpio_pic_detach(struct mvebu_gpio_softc *sc)
  368 {
  369 
  370         /*
  371          *  There has not been established any procedure yet
  372          *  how to detach PIC from living system correctly.
  373          */
  374         device_printf(sc->dev, "%s: not implemented yet\n", __func__);
  375         return (EBUSY);
  376 }
  377 
  378 static void
  379 mvebu_gpio_pic_disable_intr(device_t dev, struct intr_irqsrc *isrc)
  380 {
  381         struct mvebu_gpio_softc *sc;
  382         struct mvebu_gpio_irqsrc *mgi;
  383 
  384         sc = device_get_softc(dev);
  385         mgi = (struct mvebu_gpio_irqsrc *)isrc;
  386         mvebu_gpio_isrc_mask(sc, mgi, 0);
  387 }
  388 
  389 static void
  390 mvebu_gpio_pic_enable_intr(device_t dev, struct intr_irqsrc *isrc)
  391 {
  392         struct mvebu_gpio_softc *sc;
  393         struct mvebu_gpio_irqsrc *mgi;
  394 
  395         sc = device_get_softc(dev);
  396         mgi = (struct mvebu_gpio_irqsrc *)isrc;
  397         mvebu_gpio_isrc_mask(sc, mgi, 1);
  398 }
  399 
  400 static int
  401 mvebu_gpio_pic_map_fdt(struct mvebu_gpio_softc *sc, u_int ncells,
  402     pcell_t *cells, u_int *irqp, bool *invertedp, bool *levelp)
  403 {
  404         bool inverted, level;
  405 
  406         /*
  407          * The first cell is the interrupt number.
  408          * The second cell is used to specify flags:
  409          *      bits[3:0] trigger type and level flags:
  410          *              1 = low-to-high edge triggered.
  411          *              2 = high-to-low edge triggered.
  412          *              4 = active high level-sensitive.
  413          *              8 = active low level-sensitive.
  414          */
  415         if (ncells != 2 || cells[0] >= sc->gpio_npins)
  416                 return (EINVAL);
  417 
  418         switch (cells[1]) {
  419         case 1:
  420                 inverted  = false;
  421                 level  = false;
  422                 break;
  423         case 2:
  424                 inverted  = true;
  425                 level  = false;
  426                 break;
  427         case 4:
  428                 inverted  = false;
  429                 level  = true;
  430                 break;
  431         case 8:
  432                 inverted  = true;
  433                 level  = true;
  434                 break;
  435         default:
  436                 return (EINVAL);
  437         }
  438         *irqp = cells[0];
  439         if (invertedp != NULL)
  440                 *invertedp = inverted;
  441         if (levelp != NULL)
  442                 *levelp = level;
  443         return (0);
  444 }
  445 
  446 static int
  447 mvebu_gpio_pic_map_gpio(struct mvebu_gpio_softc *sc, u_int gpio_pin_num,
  448     u_int gpio_pin_flags, u_int intr_mode, u_int *irqp, bool *invertedp,
  449     bool *levelp)
  450 {
  451         bool inverted, level;
  452 
  453         if (gpio_pin_num >= sc->gpio_npins)
  454                 return (EINVAL);
  455 
  456         switch (intr_mode) {
  457         case GPIO_INTR_LEVEL_LOW:
  458                 inverted  = true;
  459                 level = true;
  460                 break;
  461         case GPIO_INTR_LEVEL_HIGH:
  462                 inverted  = false;
  463                 level = true;
  464                 break;
  465         case GPIO_INTR_CONFORM:
  466         case GPIO_INTR_EDGE_RISING:
  467                 inverted  = false;
  468                 level = false;
  469                 break;
  470         case GPIO_INTR_EDGE_FALLING:
  471                 inverted  = true;
  472                 level = false;
  473                 break;
  474         default:
  475                 return (EINVAL);
  476         }
  477         *irqp = gpio_pin_num;
  478         if (invertedp != NULL)
  479                 *invertedp = inverted;
  480         if (levelp != NULL)
  481                 *levelp = level;
  482         return (0);
  483 }
  484 
  485 static int
  486 mvebu_gpio_pic_map_intr(device_t dev, struct intr_map_data *data,
  487     struct intr_irqsrc **isrcp)
  488 {
  489         int rv;
  490         u_int irq;
  491         struct mvebu_gpio_softc *sc;
  492 
  493         sc = device_get_softc(dev);
  494 
  495         if (data->type == INTR_MAP_DATA_FDT) {
  496                 struct intr_map_data_fdt *daf;
  497 
  498                 daf = (struct intr_map_data_fdt *)data;
  499                 rv = mvebu_gpio_pic_map_fdt(sc, daf->ncells, daf->cells, &irq,
  500                     NULL, NULL);
  501         } else if (data->type == INTR_MAP_DATA_GPIO) {
  502                 struct intr_map_data_gpio *dag;
  503 
  504                 dag = (struct intr_map_data_gpio *)data;
  505                 rv = mvebu_gpio_pic_map_gpio(sc, dag->gpio_pin_num,
  506                    dag->gpio_pin_flags, dag->gpio_intr_mode, &irq, NULL, NULL);
  507         } else
  508                 return (ENOTSUP);
  509 
  510         if (rv == 0)
  511                 *isrcp = &sc->isrcs[irq].isrc;
  512         return (rv);
  513 }
  514 
  515 static void
  516 mvebu_gpio_pic_post_filter(device_t dev, struct intr_irqsrc *isrc)
  517 {
  518         struct mvebu_gpio_softc *sc;
  519         struct mvebu_gpio_irqsrc *mgi;
  520 
  521         sc = device_get_softc(dev);
  522         mgi = (struct mvebu_gpio_irqsrc *)isrc;
  523         if (mgi->is_level)
  524                 mvebu_gpio_isrc_eoi(sc, mgi);
  525 }
  526 
  527 static void
  528 mvebu_gpio_pic_post_ithread(device_t dev, struct intr_irqsrc *isrc)
  529 {
  530         struct mvebu_gpio_softc *sc;
  531         struct mvebu_gpio_irqsrc *mgi;
  532 
  533         sc = device_get_softc(dev);
  534         mgi = (struct mvebu_gpio_irqsrc *)isrc;
  535         mvebu_gpio_isrc_mask(sc, mgi, 1);
  536 }
  537 
  538 static void
  539 mvebu_gpio_pic_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
  540 {
  541         struct mvebu_gpio_softc *sc;
  542         struct mvebu_gpio_irqsrc *mgi;
  543 
  544         sc = device_get_softc(dev);
  545         mgi = (struct mvebu_gpio_irqsrc *)isrc;
  546 
  547         mvebu_gpio_isrc_mask(sc, mgi, 0);
  548         if (mgi->is_level)
  549                 mvebu_gpio_isrc_eoi(sc, mgi);
  550 }
  551 
  552 static int
  553 mvebu_gpio_pic_setup_intr(device_t dev, struct intr_irqsrc *isrc,
  554     struct resource *res, struct intr_map_data *data)
  555 {
  556         u_int irq;
  557         bool inverted, level;
  558         int rv;
  559         struct mvebu_gpio_softc *sc;
  560         struct mvebu_gpio_irqsrc *mgi;
  561 
  562         sc = device_get_softc(dev);
  563         mgi = (struct mvebu_gpio_irqsrc *)isrc;
  564 
  565         if (data == NULL)
  566                 return (ENOTSUP);
  567 
  568         /* Get and check config for an interrupt. */
  569         if (data->type == INTR_MAP_DATA_FDT) {
  570                 struct intr_map_data_fdt *daf;
  571 
  572                 daf = (struct intr_map_data_fdt *)data;
  573                 rv = mvebu_gpio_pic_map_fdt(sc, daf->ncells, daf->cells, &irq,
  574                     &inverted, &level);
  575         } else if (data->type == INTR_MAP_DATA_GPIO) {
  576                 struct intr_map_data_gpio *dag;
  577 
  578                 dag = (struct intr_map_data_gpio *)data;
  579                 rv = mvebu_gpio_pic_map_gpio(sc, dag->gpio_pin_num,
  580                    dag->gpio_pin_flags, dag->gpio_intr_mode, &irq,
  581                    &inverted, &level);
  582         } else
  583                 return (ENOTSUP);
  584 
  585         if (rv != 0)
  586                 return (EINVAL);
  587 
  588         /*
  589          * If this is a setup for another handler,
  590          * only check that its configuration match.
  591          */
  592         if (isrc->isrc_handlers != 0)
  593                 return (
  594                     mgi->is_level == level && mgi->is_inverted == inverted ?
  595                     0 : EINVAL);
  596 
  597         mgi->is_level = level;
  598         mgi->is_inverted = inverted;
  599         intr_modify(sc, GPIO_DATA_IN_POL, mgi, inverted ? 1 : 0, 1);
  600         mvebu_gpio_pic_enable_intr(dev, isrc);
  601 
  602         return (0);
  603 }
  604 
  605 static int
  606 mvebu_gpio_pic_teardown_intr(device_t dev, struct intr_irqsrc *isrc,
  607     struct resource *res, struct intr_map_data *data)
  608 {
  609         struct mvebu_gpio_softc *sc;
  610         struct mvebu_gpio_irqsrc *mgi;
  611 
  612         sc = device_get_softc(dev);
  613         mgi = (struct mvebu_gpio_irqsrc *)isrc;
  614 
  615         if (isrc->isrc_handlers == 0)
  616                 mvebu_gpio_isrc_mask(sc, mgi, 0);
  617         return (0);
  618 }
  619 
  620 /* --------------------------------------------------------------------------
  621  *
  622  * Bus
  623  *
  624  */
  625 
  626 static int
  627 mvebu_gpio_intr(void *arg)
  628 {
  629         u_int i, lvl, edge;
  630         struct mvebu_gpio_softc *sc;
  631         struct trapframe *tf;
  632         struct mvebu_gpio_irqsrc *mgi;
  633         struct mvebu_gpio_irq_cookie *cookie;
  634 
  635         cookie = (struct mvebu_gpio_irq_cookie *)arg;
  636         sc = cookie->sc;
  637         tf = curthread->td_intr_frame;
  638 
  639         for (i = 0; i < sc->gpio_npins; i++) {
  640                 lvl = gpio_read(sc, GPIO_DATA_IN, &sc->gpio_pins[i]);
  641                 lvl &= gpio_read(sc, GPIO_INT_LEVEL_MASK, &sc->gpio_pins[i]);
  642                 edge = gpio_read(sc, GPIO_DATA_IN, &sc->gpio_pins[i]);
  643                 edge &= gpio_read(sc, GPIO_INT_LEVEL_MASK, &sc->gpio_pins[i]);
  644                 if (edge == 0  || lvl == 0)
  645                         continue;
  646 
  647                 mgi = &sc->isrcs[i];
  648                 if (!mgi->is_level)
  649                         mvebu_gpio_isrc_eoi(sc, mgi);
  650                 if (intr_isrc_dispatch(&mgi->isrc, tf) != 0) {
  651                         mvebu_gpio_isrc_mask(sc, mgi, 0);
  652                         if (mgi->is_level)
  653                                 mvebu_gpio_isrc_eoi(sc, mgi);
  654                         device_printf(sc->dev,
  655                             "Stray irq %u disabled\n", mgi->irq);
  656                 }
  657         }
  658         return (FILTER_HANDLED);
  659 }
  660 
  661 static int
  662 mvebu_gpio_probe(device_t dev)
  663 {
  664 
  665         if (!ofw_bus_status_okay(dev))
  666                 return (ENXIO);
  667         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
  668                 return (ENXIO);
  669 
  670         device_set_desc(dev, "Marvell Integrated GPIO Controller");
  671         return (0);
  672 }
  673 
  674 static int
  675 mvebu_gpio_detach(device_t dev)
  676 {
  677         struct mvebu_gpio_softc *sc;
  678         int i;
  679 
  680         sc = device_get_softc(dev);
  681 
  682         KASSERT(mtx_initialized(&sc->mtx), ("gpio mutex not initialized"));
  683 
  684         for (i = 0; i < MV_GPIO_MAX_NIRQS; i++) {
  685                 if (sc->irq_ih[i] != NULL)
  686                         bus_teardown_intr(dev, sc->irq_res[i], sc->irq_ih[i]);
  687         }
  688 
  689         if (sc->isrcs != NULL)
  690                 mvebu_gpio_pic_detach(sc);
  691 
  692         gpiobus_detach_bus(dev);
  693 
  694         for (i = 0; i < MV_GPIO_MAX_NIRQS; i++) {
  695                 if (sc->irq_res[i] != NULL)
  696                         bus_release_resource(dev, SYS_RES_IRQ, 0,
  697                              sc->irq_res[i]);
  698         }
  699         GPIO_LOCK_DESTROY(sc);
  700 
  701         return(0);
  702 }
  703 
  704 static int
  705 mvebu_gpio_attach(device_t dev)
  706 {
  707         struct mvebu_gpio_softc *sc;
  708         phandle_t node;
  709         struct gpio_pin *pin;
  710         pcell_t pincnt;
  711         int i, rv, rid;
  712 
  713         sc = device_get_softc(dev);
  714         sc->dev = dev;
  715         node = ofw_bus_get_node(dev);
  716 
  717         GPIO_LOCK_INIT(sc);
  718 
  719         pincnt = 0;
  720         rv = OF_getencprop(node, "ngpios", &pincnt, sizeof(pcell_t));
  721         if (rv < 0) {
  722                 device_printf(dev,
  723                     "ERROR: no pin-count or ngpios entry found!\n");
  724                 return (ENXIO);
  725         }
  726 
  727         sc->gpio_npins = MIN(pincnt, MV_GPIO_MAX_NPINS);
  728         if (bootverbose)
  729                 device_printf(dev,
  730                     "%d pins available\n", sc->gpio_npins);
  731 
  732         rv = OF_getencprop(node, "offset", &sc->offset, sizeof(sc->offset));
  733         if (rv == -1) {
  734                 device_printf(dev, "ERROR: no 'offset' property found!\n");
  735                 return (ENXIO);
  736         }
  737 
  738         if (SYSCON_GET_HANDLE(sc->dev, &sc->syscon) != 0 ||
  739             sc->syscon == NULL) {
  740                 device_printf(dev, "ERROR: cannot get syscon handle!\n");
  741                 return (ENXIO);
  742         }
  743 
  744         /* Allocate interrupts. */
  745         for (i = 0; i < MV_GPIO_MAX_NIRQS; i++) {
  746                 sc->irq_cookies[i].sc = sc;
  747                 sc->irq_cookies[i].bank_num = i;
  748                 rid = i;
  749                 sc->irq_res[i] = bus_alloc_resource_any(dev, SYS_RES_IRQ,
  750                     &rid, RF_ACTIVE);
  751                 if (sc->irq_res[i] == NULL)
  752                         break;
  753                 if ((bus_setup_intr(dev, sc->irq_res[i],
  754                     INTR_TYPE_MISC | INTR_MPSAFE, mvebu_gpio_intr, NULL,
  755                     &sc->irq_cookies[i], &sc->irq_ih[i]))) {
  756                         device_printf(dev,
  757                             "WARNING: unable to register interrupt handler\n");
  758                         mvebu_gpio_detach(dev);
  759                         return (ENXIO);
  760                 }
  761         }
  762 
  763         /* Init GPIO pins */
  764         for (i = 0; i < sc->gpio_npins; i++) {
  765                 pin = sc->gpio_pins + i;
  766                 pin->gp_pin = i;
  767                 if (sc->irq_res[0] != NULL)
  768                         pin->gp_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT |
  769                             GPIO_INTR_LEVEL_LOW | GPIO_INTR_LEVEL_HIGH |
  770                             GPIO_INTR_EDGE_RISING | GPIO_INTR_EDGE_FALLING;
  771                 else
  772                         pin->gp_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
  773                 pin->gp_flags =
  774                     gpio_read(sc, GPIO_CONTROL, &sc->gpio_pins[i]) != 0 ?
  775                     GPIO_PIN_OUTPUT : GPIO_PIN_INPUT;
  776                 snprintf(pin->gp_name, GPIOMAXNAME, "gpio%d", i);
  777 
  778                 /* Init HW */
  779                 gpio_write(sc, GPIO_INT_MASK, pin, 0);
  780                 gpio_write(sc, GPIO_INT_LEVEL_MASK, pin, 0);
  781                 gpio_write(sc, GPIO_INT_CAUSE, pin, 1);
  782                 gpio_write(sc, GPIO_DATA_IN_POL, pin, 1);
  783                 gpio_write(sc, GPIO_BLINK_ENA, pin, 0);
  784         }
  785 
  786         if (sc->irq_res[0] != NULL) {
  787                 rv = mvebu_gpio_pic_attach(sc);
  788                 if (rv != 0) {
  789                         device_printf(dev, "WARNING: unable to attach PIC\n");
  790                         mvebu_gpio_detach(dev);
  791                         return (rv);
  792                 }
  793         }
  794 
  795         sc->busdev = gpiobus_attach_bus(dev);
  796         if (sc->busdev == NULL) {
  797                 mvebu_gpio_detach(dev);
  798                 return (ENXIO);
  799         }
  800 
  801         return (bus_generic_attach(dev));
  802 }
  803 
  804 static int
  805 mvebu_gpio_map_gpios(device_t dev, phandle_t pdev, phandle_t gparent,
  806     int gcells, pcell_t *gpios, uint32_t *pin, uint32_t *flags)
  807 {
  808 
  809         if (gcells != 2)
  810                 return (ERANGE);
  811         *pin = gpios[0];
  812         *flags= gpios[1];
  813         return (0);
  814 }
  815 
  816 static phandle_t
  817 mvebu_gpio_get_node(device_t bus, device_t dev)
  818 {
  819 
  820         /* We only have one child, the GPIO bus, which needs our own node. */
  821         return (ofw_bus_get_node(bus));
  822 }
  823 
  824 static device_method_t mvebu_gpio_methods[] = {
  825         DEVMETHOD(device_probe,         mvebu_gpio_probe),
  826         DEVMETHOD(device_attach,        mvebu_gpio_attach),
  827         DEVMETHOD(device_detach,        mvebu_gpio_detach),
  828 
  829         /* Interrupt controller interface */
  830         DEVMETHOD(pic_disable_intr,     mvebu_gpio_pic_disable_intr),
  831         DEVMETHOD(pic_enable_intr,      mvebu_gpio_pic_enable_intr),
  832         DEVMETHOD(pic_map_intr,         mvebu_gpio_pic_map_intr),
  833         DEVMETHOD(pic_setup_intr,       mvebu_gpio_pic_setup_intr),
  834         DEVMETHOD(pic_teardown_intr,    mvebu_gpio_pic_teardown_intr),
  835         DEVMETHOD(pic_post_filter,      mvebu_gpio_pic_post_filter),
  836         DEVMETHOD(pic_post_ithread,     mvebu_gpio_pic_post_ithread),
  837         DEVMETHOD(pic_pre_ithread,      mvebu_gpio_pic_pre_ithread),
  838 
  839         /* GPIO protocol */
  840         DEVMETHOD(gpio_get_bus,         mvebu_gpio_get_bus),
  841         DEVMETHOD(gpio_pin_max,         mvebu_gpio_pin_max),
  842         DEVMETHOD(gpio_pin_getname,     mvebu_gpio_pin_getname),
  843         DEVMETHOD(gpio_pin_getflags,    mvebu_gpio_pin_getflags),
  844         DEVMETHOD(gpio_pin_getcaps,     mvebu_gpio_pin_getcaps),
  845         DEVMETHOD(gpio_pin_setflags,    mvebu_gpio_pin_setflags),
  846         DEVMETHOD(gpio_pin_get,         mvebu_gpio_pin_get),
  847         DEVMETHOD(gpio_pin_set,         mvebu_gpio_pin_set),
  848         DEVMETHOD(gpio_pin_toggle,      mvebu_gpio_pin_toggle),
  849         DEVMETHOD(gpio_map_gpios,       mvebu_gpio_map_gpios),
  850 
  851         /* ofw_bus interface */
  852         DEVMETHOD(ofw_bus_get_node,     mvebu_gpio_get_node),
  853 
  854         DEVMETHOD_END
  855 };
  856 
  857 static devclass_t mvebu_gpio_devclass;
  858 static DEFINE_CLASS_0(gpio, mvebu_gpio_driver, mvebu_gpio_methods,
  859     sizeof(struct mvebu_gpio_softc));
  860 EARLY_DRIVER_MODULE(mvebu_gpio, simplebus, mvebu_gpio_driver,
  861      mvebu_gpio_devclass, NULL, NULL,
  862      BUS_PASS_TIMER + BUS_PASS_ORDER_LAST);

Cache object: c7080bc5100688134a796da281fbe1ca


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