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/at91/at91_pio.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 M. Warner Losh.  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 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 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: releng/9.0/sys/arm/at91/at91_pio.c 213496 2010-10-06 22:25:21Z cognet $");
   28 
   29 #include <sys/param.h>
   30 #include <sys/systm.h>
   31 #include <sys/bus.h>
   32 #include <sys/conf.h>
   33 #include <sys/kernel.h>
   34 #include <sys/lock.h>
   35 #include <sys/mbuf.h>
   36 #include <sys/malloc.h>
   37 #include <sys/module.h>
   38 #include <sys/mutex.h>
   39 #include <sys/rman.h>
   40 #include <machine/bus.h>
   41 
   42 #include <arm/at91/at91reg.h>
   43 #include <arm/at91/at91_pioreg.h>
   44 #include <arm/at91/at91_piovar.h>
   45 
   46 struct at91_pio_softc
   47 {
   48         device_t dev;                   /* Myself */
   49         void *intrhand;                 /* Interrupt handle */
   50         struct resource *irq_res;       /* IRQ resource */
   51         struct resource *mem_res;       /* Memory resource */
   52         struct mtx sc_mtx;              /* basically a perimeter lock */
   53         struct cdev *cdev;
   54         int flags;
   55 #define OPENED 1
   56 };
   57 
   58 static inline uint32_t
   59 RD4(struct at91_pio_softc *sc, bus_size_t off)
   60 {
   61         return (bus_read_4(sc->mem_res, off));
   62 }
   63 
   64 static inline void
   65 WR4(struct at91_pio_softc *sc, bus_size_t off, uint32_t val)
   66 {
   67         bus_write_4(sc->mem_res, off, val);
   68 }
   69 
   70 #define AT91_PIO_LOCK(_sc)              mtx_lock_spin(&(_sc)->sc_mtx)
   71 #define AT91_PIO_UNLOCK(_sc)            mtx_unlock_spin(&(_sc)->sc_mtx)
   72 #define AT91_PIO_LOCK_INIT(_sc) \
   73         mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \
   74             "pio", MTX_SPIN)
   75 #define AT91_PIO_LOCK_DESTROY(_sc)      mtx_destroy(&_sc->sc_mtx);
   76 #define AT91_PIO_ASSERT_LOCKED(_sc)     mtx_assert(&_sc->sc_mtx, MA_OWNED);
   77 #define AT91_PIO_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
   78 #define CDEV2SOFTC(dev)         ((dev)->si_drv1)
   79 
   80 static devclass_t at91_pio_devclass;
   81 
   82 /* bus entry points */
   83 
   84 static int at91_pio_probe(device_t dev);
   85 static int at91_pio_attach(device_t dev);
   86 static int at91_pio_detach(device_t dev);
   87 static int at91_pio_intr(void *);
   88 
   89 /* helper routines */
   90 static int at91_pio_activate(device_t dev);
   91 static void at91_pio_deactivate(device_t dev);
   92 
   93 /* cdev routines */
   94 static d_open_t at91_pio_open;
   95 static d_close_t at91_pio_close;
   96 static d_ioctl_t at91_pio_ioctl;
   97 
   98 static struct cdevsw at91_pio_cdevsw =
   99 {
  100         .d_version = D_VERSION,
  101         .d_open = at91_pio_open,
  102         .d_close = at91_pio_close,
  103         .d_ioctl = at91_pio_ioctl
  104 };
  105 
  106 static int
  107 at91_pio_probe(device_t dev)
  108 {
  109         const char *name;
  110 
  111         switch (device_get_unit(dev)) {
  112         case 0:
  113                 name = "PIOA";
  114                 break;
  115         case 1:
  116                 name = "PIOB";
  117                 break;
  118         case 2:
  119                 name = "PIOC";
  120                 break;
  121         case 3:
  122                 name = "PIOD";
  123                 break;
  124         default:
  125                 name = "PIO";
  126                 break;
  127         }
  128         device_set_desc(dev, name);
  129         return (0);
  130 }
  131 
  132 static int
  133 at91_pio_attach(device_t dev)
  134 {
  135         struct at91_pio_softc *sc = device_get_softc(dev);
  136         int err;
  137 
  138         sc->dev = dev;
  139         err = at91_pio_activate(dev);
  140         if (err)
  141                 goto out;
  142 
  143         device_printf(dev, "ABSR: %#x OSR: %#x PSR:%#x ODSR: %#x\n",
  144             RD4(sc, PIO_ABSR), RD4(sc, PIO_OSR), RD4(sc, PIO_PSR),
  145             RD4(sc, PIO_ODSR));
  146         AT91_PIO_LOCK_INIT(sc);
  147 
  148         /*
  149          * Activate the interrupt, but disable all interrupts in the hardware
  150          */
  151         WR4(sc, PIO_IDR, 0xffffffff);
  152         err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC,
  153             at91_pio_intr, NULL, sc, &sc->intrhand);
  154         if (err) {
  155                 AT91_PIO_LOCK_DESTROY(sc);
  156                 goto out;
  157         }
  158         sc->cdev = make_dev(&at91_pio_cdevsw, device_get_unit(dev), UID_ROOT,
  159             GID_WHEEL, 0600, "pio%d", device_get_unit(dev));
  160         if (sc->cdev == NULL) {
  161                 err = ENOMEM;
  162                 goto out;
  163         }
  164         sc->cdev->si_drv1 = sc;
  165 out:;
  166         if (err)
  167                 at91_pio_deactivate(dev);
  168         return (err);
  169 }
  170 
  171 static int
  172 at91_pio_detach(device_t dev)
  173 {
  174         return (EBUSY); /* XXX */
  175 }
  176 
  177 static int
  178 at91_pio_activate(device_t dev)
  179 {
  180         struct at91_pio_softc *sc;
  181         int rid;
  182 
  183         sc = device_get_softc(dev);
  184         rid = 0;
  185         sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
  186             RF_ACTIVE);
  187         if (sc->mem_res == NULL)
  188                 goto errout;
  189         rid = 0;
  190         sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
  191             RF_ACTIVE | RF_SHAREABLE);
  192         if (sc->irq_res == NULL)
  193                 goto errout;
  194         return (0);
  195 errout:
  196         at91_pio_deactivate(dev);
  197         return (ENOMEM);
  198 }
  199 
  200 static void
  201 at91_pio_deactivate(device_t dev)
  202 {
  203         struct at91_pio_softc *sc;
  204 
  205         sc = device_get_softc(dev);
  206         if (sc->intrhand)
  207                 bus_teardown_intr(dev, sc->irq_res, sc->intrhand);
  208         sc->intrhand = 0;
  209         bus_generic_detach(sc->dev);
  210         if (sc->mem_res)
  211                 bus_release_resource(dev, SYS_RES_IOPORT,
  212                     rman_get_rid(sc->mem_res), sc->mem_res);
  213         sc->mem_res = 0;
  214         if (sc->irq_res)
  215                 bus_release_resource(dev, SYS_RES_IRQ,
  216                     rman_get_rid(sc->irq_res), sc->irq_res);
  217         sc->irq_res = 0;
  218         return;
  219 }
  220 
  221 static int
  222 at91_pio_intr(void *xsc)
  223 {
  224         struct at91_pio_softc *sc = xsc;
  225 #if 0
  226         uint32_t status;
  227 
  228         /* Reading the status also clears the interrupt */
  229         status = RD4(sc, PIO_SR);
  230         if (status == 0)
  231                 return;
  232         AT91_PIO_LOCK(sc);
  233         AT91_PIO_UNLOCK(sc);
  234 #endif
  235         wakeup(sc);
  236         return (FILTER_HANDLED);
  237 }
  238 
  239 static int 
  240 at91_pio_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
  241 {
  242         struct at91_pio_softc *sc;
  243 
  244         sc = CDEV2SOFTC(dev);
  245         AT91_PIO_LOCK(sc);
  246         if (!(sc->flags & OPENED)) {
  247                 sc->flags |= OPENED;
  248 #if 0
  249         // Enable interrupts
  250 #endif
  251         }
  252         AT91_PIO_UNLOCK(sc);
  253         return (0);
  254 }
  255 
  256 static int
  257 at91_pio_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
  258 {
  259         struct at91_pio_softc *sc;
  260 
  261         sc = CDEV2SOFTC(dev);
  262         AT91_PIO_LOCK(sc);
  263         sc->flags &= ~OPENED;
  264 #if 0
  265         // Disable interrupts
  266 #endif
  267         AT91_PIO_UNLOCK(sc);
  268         return (0);
  269 }
  270 
  271 static int
  272 at91_pio_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
  273     struct thread *td)
  274 {
  275         return (ENXIO);
  276 }
  277 
  278 /*
  279  * The following functions are called early in the boot process, so
  280  * don't use bus_space, as that isn't yet available when we need to use
  281  * them.
  282  */
  283 void
  284 at91_pio_use_periph_a(uint32_t pio, uint32_t periph_a_mask, int use_pullup)
  285 {
  286         uint32_t *PIO = (uint32_t *)(AT91_BASE + pio);
  287 
  288         PIO[PIO_ASR / 4] = periph_a_mask;
  289         PIO[PIO_PDR / 4] = periph_a_mask;
  290         if (use_pullup)
  291                 PIO[PIO_PUER / 4] = periph_a_mask;
  292         else
  293                 PIO[PIO_PUDR / 4] = periph_a_mask;
  294 }
  295 
  296 void
  297 at91_pio_use_periph_b(uint32_t pio, uint32_t periph_b_mask, int use_pullup)
  298 {
  299         uint32_t *PIO = (uint32_t *)(AT91_BASE + pio);
  300 
  301         PIO[PIO_BSR / 4] = periph_b_mask;
  302         PIO[PIO_PDR / 4] = periph_b_mask;
  303         if (use_pullup)
  304                 PIO[PIO_PUER / 4] = periph_b_mask;
  305         else
  306                 PIO[PIO_PUDR / 4] = periph_b_mask;
  307 }
  308 
  309 void
  310 at91_pio_use_gpio(uint32_t pio, uint32_t gpio_mask)
  311 {
  312         uint32_t *PIO = (uint32_t *)(AT91_BASE + pio);
  313 
  314         PIO[PIO_PER / 4] = gpio_mask;
  315 }
  316 
  317 void
  318 at91_pio_gpio_input(uint32_t pio, uint32_t input_enable_mask)
  319 {
  320         uint32_t *PIO = (uint32_t *)(AT91_BASE + pio);
  321 
  322         PIO[PIO_ODR / 4] = input_enable_mask;
  323 }
  324 
  325 void
  326 at91_pio_gpio_output(uint32_t pio, uint32_t output_enable_mask, int use_pullup)
  327 {
  328         uint32_t *PIO = (uint32_t *)(AT91_BASE + pio);
  329 
  330         PIO[PIO_OER / 4] = output_enable_mask;
  331         if (use_pullup)
  332                 PIO[PIO_PUER / 4] = output_enable_mask;
  333         else
  334                 PIO[PIO_PUDR / 4] = output_enable_mask;
  335 }
  336 
  337 void
  338 at91_pio_gpio_set(uint32_t pio, uint32_t data_mask)
  339 {
  340         uint32_t *PIO = (uint32_t *)(AT91_BASE + pio);
  341 
  342         PIO[PIO_SODR / 4] = data_mask;
  343 }
  344 
  345 void
  346 at91_pio_gpio_clear(uint32_t pio, uint32_t data_mask)
  347 {
  348         uint32_t *PIO = (uint32_t *)(AT91_BASE + pio);
  349 
  350         PIO[PIO_CODR / 4] = data_mask;
  351 }
  352 
  353 uint8_t
  354 at91_pio_gpio_get(uint32_t pio, uint32_t data_mask)
  355 {
  356         uint32_t *PIO = (uint32_t *)(AT91_BASE + pio);
  357 
  358         data_mask &= PIO[PIO_PDSR / 4];
  359 
  360         return (data_mask ? 1 : 0);
  361 }
  362 
  363 void
  364 at91_pio_gpio_set_deglitch(uint32_t pio, uint32_t data_mask, int use_deglitch)
  365 {
  366         uint32_t *PIO = (uint32_t *)(AT91_BASE + pio);
  367 
  368         if (use_deglitch)
  369                 PIO[PIO_IFER / 4] = data_mask;
  370         else
  371                 PIO[PIO_IFDR / 4] = data_mask;
  372         return;
  373 }
  374 
  375 void
  376 at91_pio_gpio_set_interrupt(uint32_t pio, uint32_t data_mask, 
  377         int enable_interrupt)
  378 {
  379         uint32_t *PIO = (uint32_t *)(AT91_BASE + pio);
  380 
  381         if (enable_interrupt)
  382                 PIO[PIO_IER / 4] = data_mask;
  383         else
  384                 PIO[PIO_IDR / 4] = data_mask;
  385         return;
  386 }
  387 
  388 uint32_t
  389 at91_pio_gpio_clear_interrupt(uint32_t pio)
  390 {
  391         uint32_t *PIO = (uint32_t *)(AT91_BASE + pio);
  392         /* reading this register will clear the interrupts */
  393         return (PIO[PIO_ISR / 4]);
  394 }
  395 
  396 static device_method_t at91_pio_methods[] = {
  397         /* Device interface */
  398         DEVMETHOD(device_probe,         at91_pio_probe),
  399         DEVMETHOD(device_attach,        at91_pio_attach),
  400         DEVMETHOD(device_detach,        at91_pio_detach),
  401 
  402         { 0, 0 }
  403 };
  404 
  405 static driver_t at91_pio_driver = {
  406         "at91_pio",
  407         at91_pio_methods,
  408         sizeof(struct at91_pio_softc),
  409 };
  410 
  411 DRIVER_MODULE(at91_pio, atmelarm, at91_pio_driver, at91_pio_devclass, 0, 0);

Cache object: bdaa52abac223381ca5f83f227913491


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