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/xscale/pxa/pxa_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.  All rights reserved.
    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 ``AS IS'' AND ANY EXPRESS OR
   14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   15  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   16  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   17  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   18  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   19  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   20  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   22  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   23  */
   24 
   25 #include <sys/cdefs.h>
   26 __FBSDID("$FreeBSD$");
   27 
   28 #include <sys/param.h>
   29 #include <sys/systm.h>
   30 #include <sys/bus.h>
   31 #include <sys/kernel.h>
   32 #include <sys/lock.h>
   33 #include <sys/interrupt.h>
   34 #include <sys/module.h>
   35 #include <sys/malloc.h>
   36 #include <sys/mutex.h>
   37 #include <sys/rman.h>
   38 #include <sys/queue.h>
   39 #include <sys/taskqueue.h>
   40 #include <sys/timetc.h>
   41 #include <machine/bus.h>
   42 #include <machine/intr.h>
   43 
   44 #include <arm/xscale/pxa/pxavar.h>
   45 #include <arm/xscale/pxa/pxareg.h>
   46 
   47 struct pxa_gpio_softc {
   48         struct resource *       pg_res[4];
   49         bus_space_tag_t         pg_bst;
   50         bus_space_handle_t      pg_bsh;
   51         struct mtx              pg_mtx;
   52 
   53         uint32_t                pg_intr[3];
   54 };
   55 
   56 static struct resource_spec pxa_gpio_spec[] = {
   57         { SYS_RES_MEMORY,       0,      RF_ACTIVE },
   58         { SYS_RES_IRQ,          0,      RF_ACTIVE },
   59         { SYS_RES_IRQ,          1,      RF_ACTIVE },
   60         { SYS_RES_IRQ,          2,      RF_ACTIVE },
   61         { -1, 0 }
   62 };
   63 
   64 static struct pxa_gpio_softc *pxa_gpio_softc = NULL;
   65 
   66 static int      pxa_gpio_probe(device_t);
   67 static int      pxa_gpio_attach(device_t);
   68 
   69 static driver_filter_t  pxa_gpio_intr0;
   70 static driver_filter_t  pxa_gpio_intr1;
   71 static driver_filter_t  pxa_gpio_intrN;
   72 
   73 static int
   74 pxa_gpio_probe(device_t dev)
   75 {
   76         
   77         device_set_desc(dev, "GPIO Controller");
   78         return (0);
   79 }
   80 
   81 static int
   82 pxa_gpio_attach(device_t dev)
   83 {
   84         int     error;
   85         void    *ihl;
   86         struct  pxa_gpio_softc *sc;
   87         
   88         sc = (struct pxa_gpio_softc *)device_get_softc(dev);
   89         
   90         if (pxa_gpio_softc != NULL)
   91                 return (ENXIO);
   92         pxa_gpio_softc = sc;
   93         
   94         error = bus_alloc_resources(dev, pxa_gpio_spec, sc->pg_res);
   95         if (error) {
   96                 device_printf(dev, "could not allocate resources\n");
   97                 return (ENXIO);
   98         }
   99         
  100         sc->pg_bst = rman_get_bustag(sc->pg_res[0]);
  101         sc->pg_bsh = rman_get_bushandle(sc->pg_res[0]);
  102         
  103         /* Disable and clear all interrupts. */
  104         bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GRER0, 0);
  105         bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GRER1, 0);
  106         bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GRER2, 0);
  107         bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GFER0, 0);
  108         bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GFER1, 0);
  109         bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GFER2, 0);
  110         bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR0, ~0);
  111         bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR1, ~0);
  112         bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR2, ~0);
  113         
  114         mtx_init(&sc->pg_mtx, "GPIO mutex", NULL, MTX_SPIN);
  115         
  116         if (bus_setup_intr(dev, sc->pg_res[1], INTR_TYPE_MISC|INTR_MPSAFE,
  117             pxa_gpio_intr0, NULL, sc, &ihl) != 0) {
  118                 bus_release_resources(dev, pxa_gpio_spec, sc->pg_res);
  119                 device_printf(dev, "could not set up intr0\n");
  120                 return (ENXIO);
  121         }
  122         
  123         if (bus_setup_intr(dev, sc->pg_res[2], INTR_TYPE_MISC|INTR_MPSAFE,
  124             pxa_gpio_intr1, NULL, sc, &ihl) != 0) {
  125                 bus_release_resources(dev, pxa_gpio_spec, sc->pg_res);
  126                 device_printf(dev, "could not set up intr1\n");
  127                 return (ENXIO);
  128         }
  129         
  130         if (bus_setup_intr(dev, sc->pg_res[3], INTR_TYPE_MISC|INTR_MPSAFE,
  131             pxa_gpio_intrN, NULL, sc, &ihl) != 0) {
  132                 bus_release_resources(dev, pxa_gpio_spec, sc->pg_res);
  133                 device_printf(dev, "could not set up intrN\n");
  134                 return (ENXIO);
  135         }
  136         
  137         return (0);
  138 }
  139 
  140 static int
  141 pxa_gpio_intr0(void *arg)
  142 {
  143         struct  pxa_gpio_softc *sc;
  144         
  145         sc = (struct pxa_gpio_softc *)arg;
  146         
  147         bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR0, 0x1);
  148         sc->pg_intr[0] |= 1;
  149         
  150         return (FILTER_HANDLED);
  151 }
  152 
  153 static int
  154 pxa_gpio_intr1(void *arg)
  155 {
  156         struct  pxa_gpio_softc *sc;
  157         
  158         sc = (struct pxa_gpio_softc *)arg;
  159         
  160         bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR0, 0x2);
  161         sc->pg_intr[1] |= 2;
  162         
  163         return (FILTER_HANDLED);
  164 }
  165 
  166 static int
  167 pxa_gpio_intrN(void *arg)
  168 {
  169         uint32_t        gedr0, gedr1, gedr2;
  170         struct          pxa_gpio_softc *sc;
  171         
  172         sc = (struct pxa_gpio_softc *)arg;
  173         
  174         gedr0 = bus_space_read_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR0);
  175         gedr0 &= 0xfffffffc;
  176         bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR0, gedr0);
  177         
  178         gedr1 = bus_space_read_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR1);
  179         bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR1, gedr1);
  180         
  181         gedr2 = bus_space_read_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR2);
  182         gedr2 &= 0x001fffff;
  183         bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR2, gedr2);
  184         
  185         sc->pg_intr[0] |= gedr0;
  186         sc->pg_intr[1] |= gedr1;
  187         sc->pg_intr[2] |= gedr2;
  188         
  189         return (FILTER_HANDLED);
  190 }
  191 
  192 static device_method_t pxa_gpio_methods[] = {
  193         DEVMETHOD(device_probe, pxa_gpio_probe),
  194         DEVMETHOD(device_attach, pxa_gpio_attach),
  195         
  196         {0, 0}
  197 };
  198 
  199 static driver_t pxa_gpio_driver = {
  200         "gpio",
  201         pxa_gpio_methods,
  202         sizeof(struct pxa_gpio_softc),
  203 };
  204 
  205 static devclass_t pxa_gpio_devclass;
  206 
  207 DRIVER_MODULE(pxagpio, pxa, pxa_gpio_driver, pxa_gpio_devclass, 0, 0);
  208 
  209 #define pxagpio_reg_read(softc, reg)            \
  210         bus_space_read_4(sc->pg_bst, sc->pg_bsh, reg)
  211 #define pxagpio_reg_write(softc, reg, val)      \
  212         bus_space_write_4(sc->pg_bst, sc->pg_bsh, reg, val)
  213 
  214 uint32_t
  215 pxa_gpio_get_function(int gpio)
  216 {
  217         struct          pxa_gpio_softc *sc;
  218         uint32_t        rv, io;
  219         
  220         sc = pxa_gpio_softc;
  221         
  222         rv = pxagpio_reg_read(sc, GPIO_FN_REG(gpio)) >> GPIO_FN_SHIFT(gpio);
  223         rv = GPIO_FN(rv);
  224         
  225         io = pxagpio_reg_read(sc, PXA250_GPIO_REG(GPIO_GPDR0, gpio));
  226         if (io & GPIO_BIT(gpio))
  227                 rv |= GPIO_OUT;
  228         
  229         io = pxagpio_reg_read(sc, PXA250_GPIO_REG(GPIO_GPLR0, gpio));
  230         if (io & GPIO_BIT(gpio))
  231                 rv |= GPIO_SET;
  232         
  233         return (rv);
  234 }
  235 
  236 uint32_t
  237 pxa_gpio_set_function(int gpio, uint32_t fn)
  238 {
  239         struct          pxa_gpio_softc *sc;
  240         uint32_t        rv, bit, oldfn;
  241         
  242         sc = pxa_gpio_softc;
  243         
  244         oldfn = pxa_gpio_get_function(gpio);
  245         
  246         if (GPIO_FN(fn) == GPIO_FN(oldfn) &&
  247             GPIO_FN_IS_OUT(fn) == GPIO_FN_IS_OUT(oldfn)) {
  248                 /*
  249                  * The pin's function is not changing.
  250                  * For Alternate Functions and GPIO input, we can just
  251                  * return now.
  252                  * For GPIO output pins, check the initial state is
  253                  * the same.
  254                  *
  255                  * Return 'fn' instead of 'oldfn' so the caller can
  256                  * reliably detect that we didn't change anything.
  257                  * (The initial state might be different for non-
  258                  * GPIO output pins).
  259                  */
  260                 if (!GPIO_IS_GPIO_OUT(fn) ||
  261                     GPIO_FN_IS_SET(fn) == GPIO_FN_IS_SET(oldfn))
  262                         return (fn);
  263         }
  264         
  265         /*
  266          * See section 4.1.3.7 of the PXA2x0 Developer's Manual for
  267          * the correct procedure for changing GPIO pin functions.
  268          */
  269         
  270         bit = GPIO_BIT(gpio);
  271         
  272         /*
  273          * 1. Configure the correct set/clear state of the pin
  274          */
  275         if (GPIO_FN_IS_SET(fn))
  276                 pxagpio_reg_write(sc, PXA250_GPIO_REG(GPIO_GPSR0, gpio), bit);
  277         else
  278                 pxagpio_reg_write(sc, PXA250_GPIO_REG(GPIO_GPCR0, gpio), bit);
  279         
  280         /*
  281          * 2. Configure the pin as an input or output as appropriate
  282          */
  283         rv = pxagpio_reg_read(sc, PXA250_GPIO_REG(GPIO_GPDR0, gpio)) & ~bit;
  284         if (GPIO_FN_IS_OUT(fn))
  285                 rv |= bit;
  286         pxagpio_reg_write(sc, PXA250_GPIO_REG(GPIO_GPDR0, gpio), rv);
  287         
  288         /*
  289          * 3. Configure the pin's function
  290          */
  291         bit = GPIO_FN_MASK << GPIO_FN_SHIFT(gpio);
  292         fn = GPIO_FN(fn) << GPIO_FN_SHIFT(gpio);
  293         rv = pxagpio_reg_read(sc, GPIO_FN_REG(gpio)) & ~bit;
  294         pxagpio_reg_write(sc, GPIO_FN_REG(gpio), rv | fn);
  295         
  296         return (oldfn);
  297 }
  298 
  299 /*
  300  * GPIO "interrupt" handling.
  301  */
  302 
  303 void
  304 pxa_gpio_mask_irq(int irq)
  305 {
  306         uint32_t        val;
  307         struct          pxa_gpio_softc *sc;
  308         int             gpio;
  309         
  310         sc = pxa_gpio_softc;
  311         gpio = IRQ_TO_GPIO(irq);
  312         
  313         val = pxagpio_reg_read(sc, PXA250_GPIO_REG(GPIO_GRER0, gpio));
  314         val &= ~GPIO_BIT(gpio);
  315         pxagpio_reg_write(sc, PXA250_GPIO_REG(GPIO_GRER0, gpio), val);
  316 }
  317 
  318 void
  319 pxa_gpio_unmask_irq(int irq)
  320 {
  321         uint32_t        val;
  322         struct          pxa_gpio_softc *sc;
  323         int             gpio;
  324         
  325         sc = pxa_gpio_softc;
  326         gpio = IRQ_TO_GPIO(irq);
  327         
  328         val = pxagpio_reg_read(sc, PXA250_GPIO_REG(GPIO_GRER0, gpio));
  329         val |= GPIO_BIT(gpio);
  330         pxagpio_reg_write(sc, PXA250_GPIO_REG(GPIO_GRER0, gpio), val);
  331 }
  332 
  333 int
  334 pxa_gpio_get_next_irq()
  335 {
  336         struct  pxa_gpio_softc *sc;
  337         int     gpio;
  338         
  339         sc = pxa_gpio_softc;
  340         
  341         if (sc->pg_intr[0] != 0) {
  342                 gpio = ffs(sc->pg_intr[0]) - 1;
  343                 sc->pg_intr[0] &= ~(1 << gpio);
  344                 return (GPIO_TO_IRQ(gpio));
  345         }
  346         if (sc->pg_intr[1] != 0) {
  347                 gpio = ffs(sc->pg_intr[1]) - 1;
  348                 sc->pg_intr[1] &= ~(1 << gpio);
  349                 return (GPIO_TO_IRQ(gpio + 32));
  350         }
  351         if (sc->pg_intr[2] != 0) {
  352                 gpio = ffs(sc->pg_intr[2]) - 1;
  353                 sc->pg_intr[2] &= ~(1 << gpio);
  354                 return (GPIO_TO_IRQ(gpio + 64));
  355         }
  356 
  357         return (-1);
  358 }

Cache object: 6b27dc9b865c6c09efc93d7a492dfe53


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