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/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) 2006 Benno Rice.
    3  * Copyright (C) 2008 MARVELL INTERNATIONAL LTD.
    4  * All rights reserved.
    5  *
    6  * Adapted and extended for Marvell SoCs by Semihalf.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   27  *
   28  * from: FreeBSD: //depot/projects/arm/src/sys/arm/xscale/pxa2x0/pxa2x0_gpio.c, rev 1
   29  */
   30 
   31 #include <sys/cdefs.h>
   32 __FBSDID("$FreeBSD: releng/8.3/sys/arm/mv/gpio.c 191140 2009-04-16 11:20:18Z raj $");
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/bus.h>
   37 #include <sys/kernel.h>
   38 #include <sys/lock.h>
   39 #include <sys/interrupt.h>
   40 #include <sys/module.h>
   41 #include <sys/malloc.h>
   42 #include <sys/mutex.h>
   43 #include <sys/rman.h>
   44 #include <sys/queue.h>
   45 #include <sys/timetc.h>
   46 #include <machine/bus.h>
   47 #include <machine/intr.h>
   48 
   49 #include <arm/mv/mvvar.h>
   50 #include <arm/mv/mvreg.h>
   51 
   52 #define GPIO_MAX_INTR_COUNT     8
   53 #define GPIO_PINS_PER_REG       32
   54 
   55 struct mv_gpio_softc {
   56         struct resource *       res[GPIO_MAX_INTR_COUNT + 1];
   57         void                    *ih_cookie[GPIO_MAX_INTR_COUNT];
   58         bus_space_tag_t         bst;
   59         bus_space_handle_t      bsh;
   60         uint8_t                 pin_num;        /* number of GPIO pins */
   61         uint8_t                 irq_num;        /* number of real IRQs occupied by GPIO controller */
   62         uint8_t                 use_high;
   63 };
   64 
   65 extern struct resource_spec mv_gpio_res[];
   66 
   67 static struct mv_gpio_softc *mv_gpio_softc = NULL;
   68 static uint32_t gpio_setup[MV_GPIO_MAX_NPINS];
   69 
   70 static int      mv_gpio_probe(device_t);
   71 static int      mv_gpio_attach(device_t);
   72 static void     mv_gpio_intr(void *);
   73 
   74 static void     mv_gpio_intr_handler(int pin);
   75 static uint32_t mv_gpio_reg_read(uint32_t reg);
   76 static void     mv_gpio_reg_write(uint32_t reg, uint32_t val);
   77 static void     mv_gpio_reg_set(uint32_t reg, uint32_t val);
   78 static void     mv_gpio_reg_clear(uint32_t reg, uint32_t val);
   79 
   80 static void     mv_gpio_blink(uint32_t pin, uint8_t enable);
   81 static void     mv_gpio_polarity(uint32_t pin, uint8_t enable);
   82 static void     mv_gpio_level(uint32_t pin, uint8_t enable);
   83 static void     mv_gpio_edge(uint32_t pin, uint8_t enable);
   84 static void     mv_gpio_out_en(uint32_t pin, uint8_t enable);
   85 static void     mv_gpio_int_ack(uint32_t pin);
   86 static void     mv_gpio_value_set(uint32_t pin, uint8_t val);
   87 static uint32_t mv_gpio_value_get(uint32_t pin);
   88 
   89 static device_method_t mv_gpio_methods[] = {
   90         DEVMETHOD(device_probe,         mv_gpio_probe),
   91         DEVMETHOD(device_attach,        mv_gpio_attach),
   92         { 0, 0 }
   93 };
   94 
   95 static driver_t mv_gpio_driver = {
   96         "gpio",
   97         mv_gpio_methods,
   98         sizeof(struct mv_gpio_softc),
   99 };
  100 
  101 static devclass_t mv_gpio_devclass;
  102 
  103 DRIVER_MODULE(gpio, mbus, mv_gpio_driver, mv_gpio_devclass, 0, 0);
  104 
  105 static int
  106 mv_gpio_probe(device_t dev)
  107 {
  108 
  109         device_set_desc(dev, "Marvell Integrated GPIO Controller");
  110         return (0);
  111 }
  112 
  113 static int
  114 mv_gpio_attach(device_t dev)
  115 {
  116         int error, i;
  117         struct mv_gpio_softc *sc;
  118         uint32_t dev_id, rev_id;
  119 
  120         sc = (struct mv_gpio_softc *)device_get_softc(dev);
  121 
  122         if (mv_gpio_softc != NULL)
  123                 return (ENXIO);
  124         mv_gpio_softc = sc;
  125 
  126         /* Get chip id and revision */
  127         soc_id(&dev_id, &rev_id);
  128 
  129         if (dev_id == MV_DEV_88F5182 ||
  130             dev_id == MV_DEV_88F5281 ||
  131             dev_id == MV_DEV_MV78100 ||
  132             dev_id == MV_DEV_MV78100_Z0 ) {
  133                 sc->pin_num = 32;
  134                 sc->irq_num = 4;
  135                 sc->use_high = 0;
  136 
  137         } else if (dev_id == MV_DEV_88F6281) {
  138                 sc->pin_num = 50;
  139                 sc->irq_num = 7;
  140                 sc->use_high = 1;
  141 
  142         } else {
  143                 device_printf(dev, "unknown chip id=0x%x\n", dev_id);
  144                 return (ENXIO);
  145         }
  146 
  147         error = bus_alloc_resources(dev, mv_gpio_res, sc->res);
  148         if (error) {
  149                 device_printf(dev, "could not allocate resources\n");
  150                 return (ENXIO);
  151         }
  152 
  153         sc->bst = rman_get_bustag(sc->res[0]);
  154         sc->bsh = rman_get_bushandle(sc->res[0]);
  155 
  156         /* Disable and clear all interrupts */
  157         bus_space_write_4(sc->bst, sc->bsh, GPIO_INT_EDGE_MASK, 0);
  158         bus_space_write_4(sc->bst, sc->bsh, GPIO_INT_LEV_MASK, 0);
  159         bus_space_write_4(sc->bst, sc->bsh, GPIO_INT_CAUSE, 0);
  160 
  161         if (sc->use_high) {
  162                 bus_space_write_4(sc->bst, sc->bsh,
  163                     GPIO_HI_INT_EDGE_MASK, 0);
  164                 bus_space_write_4(sc->bst, sc->bsh,
  165                     GPIO_HI_INT_LEV_MASK, 0);
  166                 bus_space_write_4(sc->bst, sc->bsh,
  167                     GPIO_HI_INT_CAUSE, 0);
  168         }
  169 
  170         for (i = 0; i < sc->irq_num; i++) {
  171                 if (bus_setup_intr(dev, sc->res[1 + i],
  172                     INTR_TYPE_MISC | INTR_FAST,
  173                     (driver_filter_t *)mv_gpio_intr, NULL,
  174                     sc, &sc->ih_cookie[i]) != 0) {
  175                         bus_release_resources(dev, mv_gpio_res, sc->res);
  176                         device_printf(dev, "could not set up intr %d\n", i);
  177                         return (ENXIO);
  178                 }
  179         }
  180 
  181         /* Setup GPIO lines */
  182         for (i = 0; mv_gpio_config[i].gc_gpio >= 0; i++) {
  183                 mv_gpio_configure(mv_gpio_config[i].gc_gpio,
  184                     mv_gpio_config[i].gc_flags, ~0u);
  185 
  186                 if (mv_gpio_config[i].gc_output < 0)
  187                         mv_gpio_out_en(mv_gpio_config[i].gc_gpio, 0);
  188                 else
  189                         mv_gpio_out(mv_gpio_config[i].gc_gpio,
  190                             mv_gpio_config[i].gc_output, 1);
  191         }
  192 
  193         return (0);
  194 }
  195 
  196 static void
  197 mv_gpio_intr(void *arg)
  198 {
  199         uint32_t int_cause, gpio_val;
  200         uint32_t int_cause_hi, gpio_val_hi = 0;
  201         int i;
  202 
  203         int_cause = mv_gpio_reg_read(GPIO_INT_CAUSE);
  204         gpio_val = mv_gpio_reg_read(GPIO_DATA_IN);
  205         gpio_val &= int_cause;
  206         if (mv_gpio_softc->use_high) {
  207                 int_cause_hi = mv_gpio_reg_read(GPIO_HI_INT_CAUSE);
  208                 gpio_val_hi = mv_gpio_reg_read(GPIO_HI_DATA_IN);
  209                 gpio_val_hi &= int_cause_hi;
  210         }
  211 
  212         i = 0;
  213         while (gpio_val != 0) {
  214                 if (gpio_val & 1)
  215                         mv_gpio_intr_handler(i);
  216                 gpio_val >>= 1;
  217                 i++;
  218         }
  219 
  220         if (mv_gpio_softc->use_high) {
  221                 i = 0;
  222                 while (gpio_val_hi != 0) {
  223                         if (gpio_val_hi & 1)
  224                                 mv_gpio_intr_handler(i + GPIO_PINS_PER_REG);
  225                         gpio_val_hi >>= 1;
  226                         i++;
  227                 }
  228         }
  229 }
  230 
  231 /*
  232  * GPIO interrupt handling
  233  */
  234 
  235 static struct intr_event *gpio_events[MV_GPIO_MAX_NPINS];
  236 
  237 int
  238 mv_gpio_setup_intrhandler(const char *name, driver_filter_t *filt,
  239     void (*hand)(void *), void *arg, int pin, int flags, void **cookiep)
  240 {
  241         struct  intr_event *event;
  242         int     error;
  243 
  244         if (pin < 0 || pin >= mv_gpio_softc->pin_num)
  245                 return (ENXIO);
  246         event = gpio_events[pin];
  247         if (event == NULL) {
  248                 error = intr_event_create(&event, (void *)pin, 0, pin,
  249                     (void (*)(void *))mv_gpio_intr_mask,
  250                     (void (*)(void *))mv_gpio_intr_unmask,
  251                     (void (*)(void *))mv_gpio_int_ack,
  252                     NULL,
  253                     "gpio%d:", pin);
  254                 if (error != 0)
  255                         return (error);
  256                 gpio_events[pin] = event;
  257         }
  258 
  259         intr_event_add_handler(event, name, filt, hand, arg,
  260             intr_priority(flags), flags, cookiep);
  261         return (0);
  262 }
  263 
  264 void
  265 mv_gpio_intr_mask(int pin)
  266 {
  267 
  268         if (pin >= mv_gpio_softc->pin_num)
  269                 return;
  270 
  271         if (gpio_setup[pin] & MV_GPIO_EDGE)
  272                 mv_gpio_edge(pin, 0);
  273         else
  274                 mv_gpio_level(pin, 0);
  275 }
  276 
  277 void
  278 mv_gpio_intr_unmask(int pin)
  279 {
  280 
  281         if (pin >= mv_gpio_softc->pin_num)
  282                 return;
  283 
  284         if (gpio_setup[pin] & MV_GPIO_EDGE)
  285                 mv_gpio_edge(pin, 1);
  286         else
  287                 mv_gpio_level(pin, 1);
  288 }
  289 
  290 static void
  291 mv_gpio_intr_handler(int pin)
  292 {
  293         struct intr_event *event;
  294 
  295         event = gpio_events[pin];
  296         if (event == NULL || TAILQ_EMPTY(&event->ie_handlers))
  297                 return;
  298 
  299         intr_event_handle(event, NULL);
  300 }
  301 
  302 int
  303 mv_gpio_configure(uint32_t pin, uint32_t flags, uint32_t mask)
  304 {
  305 
  306         if (pin >= mv_gpio_softc->pin_num)
  307                 return (EINVAL);
  308 
  309         if (mask & MV_GPIO_BLINK)
  310                 mv_gpio_blink(pin, flags & MV_GPIO_BLINK);
  311         if (mask & MV_GPIO_POLAR_LOW)
  312                 mv_gpio_polarity(pin, flags & MV_GPIO_POLAR_LOW);
  313         if (mask & MV_GPIO_EDGE)
  314                 mv_gpio_edge(pin, flags & MV_GPIO_EDGE);
  315         if (mask & MV_GPIO_LEVEL)
  316                 mv_gpio_level(pin, flags & MV_GPIO_LEVEL);
  317 
  318         gpio_setup[pin] &= ~(mask);
  319         gpio_setup[pin] |= (flags & mask);
  320 
  321         return (0);
  322 }
  323 
  324 void
  325 mv_gpio_out(uint32_t pin, uint8_t val, uint8_t enable)
  326 {
  327 
  328         mv_gpio_value_set(pin, val);
  329         mv_gpio_out_en(pin, enable);
  330 }
  331 
  332 uint8_t
  333 mv_gpio_in(uint32_t pin)
  334 {
  335 
  336         return (mv_gpio_value_get(pin));
  337 }
  338 
  339 static uint32_t
  340 mv_gpio_reg_read(uint32_t reg)
  341 {
  342 
  343         return (bus_space_read_4(mv_gpio_softc->bst,
  344             mv_gpio_softc->bsh, reg));
  345 }
  346 
  347 static void
  348 mv_gpio_reg_write(uint32_t reg, uint32_t val)
  349 {
  350 
  351         bus_space_write_4(mv_gpio_softc->bst,
  352             mv_gpio_softc->bsh, reg, val);
  353 }
  354 
  355 static void
  356 mv_gpio_reg_set(uint32_t reg, uint32_t pin)
  357 {
  358         uint32_t reg_val;
  359 
  360         reg_val = mv_gpio_reg_read(reg);
  361         reg_val |= GPIO(pin);
  362         mv_gpio_reg_write(reg, reg_val);
  363 }
  364 
  365 static void
  366 mv_gpio_reg_clear(uint32_t reg, uint32_t pin)
  367 {
  368         uint32_t reg_val;
  369 
  370         reg_val = mv_gpio_reg_read(reg);
  371         reg_val &= ~(GPIO(pin));
  372         mv_gpio_reg_write(reg, reg_val);
  373 }
  374 
  375 static void
  376 mv_gpio_out_en(uint32_t pin, uint8_t enable)
  377 {
  378         uint32_t reg;
  379 
  380         if (pin >= mv_gpio_softc->pin_num)
  381                 return;
  382 
  383         if (pin >= GPIO_PINS_PER_REG) {
  384                 reg = GPIO_HI_DATA_OUT_EN_CTRL;
  385                 pin -= GPIO_PINS_PER_REG;
  386         } else
  387                 reg = GPIO_DATA_OUT_EN_CTRL;
  388 
  389         if (enable)
  390                 mv_gpio_reg_clear(reg, pin);
  391         else
  392                 mv_gpio_reg_set(reg, pin);
  393 }
  394 
  395 static void
  396 mv_gpio_blink(uint32_t pin, uint8_t enable)
  397 {
  398         uint32_t reg;
  399 
  400         if (pin >= mv_gpio_softc->pin_num)
  401                 return;
  402 
  403         if (pin >= GPIO_PINS_PER_REG) {
  404                 reg = GPIO_HI_BLINK_EN;
  405                 pin -= GPIO_PINS_PER_REG;
  406         } else
  407                 reg = GPIO_BLINK_EN;
  408 
  409         if (enable)
  410                 mv_gpio_reg_set(reg, pin);
  411         else
  412                 mv_gpio_reg_clear(reg, pin);
  413 }
  414 
  415 static void
  416 mv_gpio_polarity(uint32_t pin, uint8_t enable)
  417 {
  418         uint32_t reg;
  419 
  420         if (pin >= mv_gpio_softc->pin_num)
  421                 return;
  422 
  423         if (pin >= GPIO_PINS_PER_REG) {
  424                 reg = GPIO_HI_DATA_IN_POLAR;
  425                 pin -= GPIO_PINS_PER_REG;
  426         } else
  427                 reg = GPIO_DATA_IN_POLAR;
  428 
  429         if (enable)
  430                 mv_gpio_reg_set(reg, pin);
  431         else
  432                 mv_gpio_reg_clear(reg, pin);
  433 }
  434 
  435 static void
  436 mv_gpio_level(uint32_t pin, uint8_t enable)
  437 {
  438         uint32_t reg;
  439 
  440         if (pin >= mv_gpio_softc->pin_num)
  441                 return;
  442 
  443         if (pin >= GPIO_PINS_PER_REG) {
  444                 reg = GPIO_HI_INT_LEV_MASK;
  445                 pin -= GPIO_PINS_PER_REG;
  446         } else
  447                 reg = GPIO_INT_LEV_MASK;
  448 
  449         if (enable)
  450                 mv_gpio_reg_set(reg, pin);
  451         else
  452                 mv_gpio_reg_clear(reg, pin);
  453 }
  454 
  455 static void
  456 mv_gpio_edge(uint32_t pin, uint8_t enable)
  457 {
  458         uint32_t reg;
  459 
  460         if (pin >= mv_gpio_softc->pin_num)
  461                 return;
  462 
  463         if (pin >= GPIO_PINS_PER_REG) {
  464                 reg = GPIO_HI_INT_EDGE_MASK;
  465                 pin -= GPIO_PINS_PER_REG;
  466         } else
  467                 reg = GPIO_INT_EDGE_MASK;
  468 
  469         if (enable)
  470                 mv_gpio_reg_set(reg, pin);
  471         else
  472                 mv_gpio_reg_clear(reg, pin);
  473 }
  474 
  475 static void
  476 mv_gpio_int_ack(uint32_t pin)
  477 {
  478         uint32_t reg;
  479 
  480         if (pin >= mv_gpio_softc->pin_num)
  481                 return;
  482 
  483         if (pin >= GPIO_PINS_PER_REG) {
  484                 reg = GPIO_HI_INT_CAUSE;
  485                 pin -= GPIO_PINS_PER_REG;
  486         } else
  487                 reg = GPIO_INT_CAUSE;
  488 
  489         mv_gpio_reg_clear(reg, pin);
  490 }
  491 
  492 static uint32_t
  493 mv_gpio_value_get(uint32_t pin)
  494 {
  495         uint32_t reg, reg_val;
  496 
  497         if (pin >= mv_gpio_softc->pin_num)
  498                 return (0);
  499 
  500         if (pin >= GPIO_PINS_PER_REG) {
  501                 reg = GPIO_HI_DATA_IN;
  502                 pin -= GPIO_PINS_PER_REG;
  503         } else
  504                 reg = GPIO_DATA_IN;
  505 
  506         reg_val = mv_gpio_reg_read(reg);
  507 
  508         return (reg_val & GPIO(pin));
  509 }
  510 
  511 static void
  512 mv_gpio_value_set(uint32_t pin, uint8_t val)
  513 {
  514         uint32_t reg;
  515 
  516         if (pin >= mv_gpio_softc->pin_num)
  517                 return;
  518 
  519         if (pin >= GPIO_PINS_PER_REG) {
  520                 reg = GPIO_HI_DATA_OUT;
  521                 pin -= GPIO_PINS_PER_REG;
  522         } else
  523                 reg = GPIO_DATA_OUT;
  524 
  525         if (val)
  526                 mv_gpio_reg_set(reg, pin);
  527         else
  528                 mv_gpio_reg_clear(reg, pin);
  529 }

Cache object: ddd57aecc258779c09158407fedd89db


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