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_spi.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 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: releng/6.3/sys/arm/at91/at91_spi.c 160477 2006-07-18 20:30:37Z imp $");
   27 
   28 #include <sys/param.h>
   29 #include <sys/systm.h>
   30 #include <sys/bus.h>
   31 #include <sys/conf.h>
   32 #include <sys/kernel.h>
   33 #include <sys/lock.h>
   34 #include <sys/mbuf.h>
   35 #include <sys/malloc.h>
   36 #include <sys/module.h>
   37 #include <sys/mutex.h>
   38 #include <sys/rman.h>
   39 #include <machine/bus.h>
   40 
   41 #include <arm/at91/at91_spireg.h>
   42 #include <arm/at91/at91_pdcreg.h>
   43 
   44 #include <dev/spibus/spi.h>
   45 #include "spibus_if.h"
   46 
   47 struct at91_spi_softc
   48 {
   49         device_t dev;                   /* Myself */
   50         void *intrhand;                 /* Interrupt handle */
   51         struct resource *irq_res;       /* IRQ resource */
   52         struct resource *mem_res;       /* Memory resource */
   53         struct mtx sc_mtx;              /* basically a perimeter lock */
   54         bus_dma_tag_t dmatag;           /* bus dma tag for mbufs */
   55         bus_dmamap_t map[4];            /* Maps for the transaction */
   56 };
   57 
   58 static inline uint32_t
   59 RD4(struct at91_spi_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_spi_softc *sc, bus_size_t off, uint32_t val)
   66 {
   67         bus_write_4(sc->mem_res, off, val);
   68 }
   69 
   70 #define AT91_SPI_LOCK(_sc)              mtx_lock(&(_sc)->sc_mtx)
   71 #define AT91_SPI_UNLOCK(_sc)            mtx_unlock(&(_sc)->sc_mtx)
   72 #define AT91_SPI_LOCK_INIT(_sc) \
   73         mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \
   74             "spi", MTX_DEF)
   75 #define AT91_SPI_LOCK_DESTROY(_sc)      mtx_destroy(&_sc->sc_mtx);
   76 #define AT91_SPI_ASSERT_LOCKED(_sc)     mtx_assert(&_sc->sc_mtx, MA_OWNED);
   77 #define AT91_SPI_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
   78 
   79 static devclass_t at91_spi_devclass;
   80 
   81 /* bus entry points */
   82 
   83 static int at91_spi_probe(device_t dev);
   84 static int at91_spi_attach(device_t dev);
   85 static int at91_spi_detach(device_t dev);
   86 
   87 /* helper routines */
   88 static int at91_spi_activate(device_t dev);
   89 static void at91_spi_deactivate(device_t dev);
   90 
   91 static int
   92 at91_spi_probe(device_t dev)
   93 {
   94         device_set_desc(dev, "SPI");
   95         return (0);
   96 }
   97 
   98 static int
   99 at91_spi_attach(device_t dev)
  100 {
  101         struct at91_spi_softc *sc = device_get_softc(dev);
  102         int err, i;
  103 
  104         sc->dev = dev;
  105         err = at91_spi_activate(dev);
  106         if (err)
  107                 goto out;
  108 
  109         AT91_SPI_LOCK_INIT(sc);
  110 
  111         /*
  112          * Allocate DMA tags and maps
  113          */
  114         err = bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT,
  115             BUS_SPACE_MAXADDR, NULL, NULL, 2058, 1, 2048, BUS_DMA_ALLOCNOW,
  116             NULL, NULL, &sc->dmatag);
  117         if (err != 0)
  118                 goto out;
  119         for (i = 0; i < 4; i++) {
  120                 err = bus_dmamap_create(sc->dmatag, 0,  &sc->map[i]);
  121                 if (err != 0)
  122                         goto out;
  123         }
  124 
  125         // reset the SPI
  126         WR4(sc, SPI_CR, SPI_CR_SWRST);
  127 
  128         WR4(sc, SPI_MR, (0xf << 24) | SPI_MR_MSTR | SPI_MR_MODFDIS |
  129             (0xE << 16));
  130 
  131         WR4(sc, SPI_CSR0, SPI_CSR_CPOL | (4 << 16) | (2 << 8));
  132         WR4(sc, SPI_CR, SPI_CR_SPIEN);
  133 
  134         WR4(sc, PDC_PTCR, PDC_PTCR_TXTDIS);
  135         WR4(sc, PDC_PTCR, PDC_PTCR_RXTDIS);
  136         WR4(sc, PDC_RNPR, 0);
  137         WR4(sc, PDC_RNCR, 0);
  138         WR4(sc, PDC_TNPR, 0);
  139         WR4(sc, PDC_TNCR, 0);
  140         WR4(sc, PDC_RPR, 0);
  141         WR4(sc, PDC_RCR, 0);
  142         WR4(sc, PDC_TPR, 0);
  143         WR4(sc, PDC_TCR, 0);
  144         WR4(sc, PDC_PTCR, PDC_PTCR_RXTEN);
  145         WR4(sc, PDC_PTCR, PDC_PTCR_TXTEN);
  146         RD4(sc, SPI_RDR);
  147         RD4(sc, SPI_SR);
  148 
  149         device_add_child(dev, "spibus", -1);
  150         bus_generic_attach(dev);
  151 out:;
  152         if (err)
  153                 at91_spi_deactivate(dev);
  154         return (err);
  155 }
  156 
  157 static int
  158 at91_spi_detach(device_t dev)
  159 {
  160         return (EBUSY); /* XXX */
  161 }
  162 
  163 static int
  164 at91_spi_activate(device_t dev)
  165 {
  166         struct at91_spi_softc *sc;
  167         int rid;
  168 
  169         sc = device_get_softc(dev);
  170         rid = 0;
  171         sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
  172             RF_ACTIVE);
  173         if (sc->mem_res == NULL)
  174                 goto errout;
  175         rid = 0;
  176         sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
  177             RF_ACTIVE);
  178         if (sc->mem_res == NULL)
  179                 goto errout;
  180         return (0);
  181 errout:
  182         at91_spi_deactivate(dev);
  183         return (ENOMEM);
  184 }
  185 
  186 static void
  187 at91_spi_deactivate(device_t dev)
  188 {
  189         struct at91_spi_softc *sc;
  190 
  191         sc = device_get_softc(dev);
  192         if (sc->intrhand)
  193                 bus_teardown_intr(dev, sc->irq_res, sc->intrhand);
  194         sc->intrhand = 0;
  195         bus_generic_detach(sc->dev);
  196         if (sc->mem_res)
  197                 bus_release_resource(dev, SYS_RES_IOPORT,
  198                     rman_get_rid(sc->mem_res), sc->mem_res);
  199         sc->mem_res = 0;
  200         if (sc->irq_res)
  201                 bus_release_resource(dev, SYS_RES_IRQ,
  202                     rman_get_rid(sc->irq_res), sc->irq_res);
  203         sc->irq_res = 0;
  204         return;
  205 }
  206 
  207 static void
  208 at91_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
  209 {
  210         if (error != 0)
  211                 return;
  212         *(bus_addr_t *)arg = segs[0].ds_addr;
  213 }
  214 
  215 static int
  216 at91_spi_transfer(device_t dev, device_t child, struct spi_command *cmd)
  217 {
  218         struct at91_spi_softc *sc;
  219         int i;
  220         bus_addr_t addr;
  221 
  222         sc = device_get_softc(dev);
  223         WR4(sc, PDC_PTCR, PDC_PTCR_TXTDIS | PDC_PTCR_RXTDIS);
  224         i = 0;
  225         if (bus_dmamap_load(sc->dmatag, sc->map[i], cmd->tx_cmd,
  226             cmd->tx_cmd_sz, at91_getaddr, &addr, 0) != 0)
  227                 goto out;
  228         WR4(sc, PDC_TPR, addr);
  229         WR4(sc, PDC_TCR, cmd->tx_cmd_sz);
  230         bus_dmamap_sync(sc->dmatag, sc->map[i], BUS_DMASYNC_PREWRITE);
  231         i++;
  232         if (bus_dmamap_load(sc->dmatag, sc->map[i], cmd->tx_data,
  233             cmd->tx_data_sz, at91_getaddr, &addr, 0) != 0)
  234                 goto out;
  235         WR4(sc, PDC_TNPR, addr);
  236         WR4(sc, PDC_TNCR, cmd->tx_cmd_sz);
  237         bus_dmamap_sync(sc->dmatag, sc->map[i], BUS_DMASYNC_PREWRITE);
  238         i++;
  239         if (bus_dmamap_load(sc->dmatag, sc->map[i], cmd->rx_cmd,
  240             cmd->tx_cmd_sz, at91_getaddr, &addr, 0) != 0)
  241                 goto out;
  242         WR4(sc, PDC_RPR, addr);
  243         WR4(sc, PDC_RCR, cmd->tx_cmd_sz);
  244         bus_dmamap_sync(sc->dmatag, sc->map[i], BUS_DMASYNC_PREREAD);
  245         i++;
  246         if (bus_dmamap_load(sc->dmatag, sc->map[i], cmd->rx_data,
  247             cmd->tx_data_sz, at91_getaddr, &addr, 0) != 0)
  248                 goto out;
  249         WR4(sc, PDC_RNPR, addr);
  250         WR4(sc, PDC_RNCR, cmd->tx_data_sz);
  251         bus_dmamap_sync(sc->dmatag, sc->map[i], BUS_DMASYNC_PREREAD);
  252 
  253         WR4(sc, PDC_PTCR, PDC_PTCR_TXTEN | PDC_PTCR_RXTEN);
  254 
  255         // wait for completion
  256         // XXX should be done as an ISR of some sort.
  257         while (RD4(sc, SPI_SR) & SPI_SR_ENDRX)
  258                 DELAY(700);
  259 
  260         // Sync the buffers after the DMA is done, and unload them.
  261         bus_dmamap_sync(sc->dmatag, sc->map[0], BUS_DMASYNC_POSTWRITE);
  262         bus_dmamap_sync(sc->dmatag, sc->map[1], BUS_DMASYNC_POSTWRITE);
  263         bus_dmamap_sync(sc->dmatag, sc->map[2], BUS_DMASYNC_POSTREAD);
  264         bus_dmamap_sync(sc->dmatag, sc->map[3], BUS_DMASYNC_POSTREAD);
  265         for (i = 0; i < 4; i++)
  266                 bus_dmamap_unload(sc->dmatag, sc->map[i]);
  267         return (0);
  268 out:;
  269         while (i-- > 0)
  270                 bus_dmamap_unload(sc->dmatag, sc->map[i]);
  271         return (EIO);
  272 }
  273 
  274 static device_method_t at91_spi_methods[] = {
  275         /* Device interface */
  276         DEVMETHOD(device_probe,         at91_spi_probe),
  277         DEVMETHOD(device_attach,        at91_spi_attach),
  278         DEVMETHOD(device_detach,        at91_spi_detach),
  279 
  280         /* spibus interface */
  281         DEVMETHOD(spibus_transfer,      at91_spi_transfer),
  282         { 0, 0 }
  283 };
  284 
  285 static driver_t at91_spi_driver = {
  286         "at91_spi",
  287         at91_spi_methods,
  288         sizeof(struct at91_spi_softc),
  289 };
  290 
  291 DRIVER_MODULE(at91_spi, atmelarm, at91_spi_driver, at91_spi_devclass, 0, 0);

Cache object: 2f6aac5190a2c4c2b076e4e6d661901b


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