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 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_spi.c 192059 2009-05-13 18:42:49Z gonzo $");
   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/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         bus_dma_tag_t dmatag;           /* bus dma tag for mbufs */
   54         bus_dmamap_t map[4];            /* Maps for the transaction */
   55         int rxdone;
   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 /* bus entry points */
   71 static int at91_spi_probe(device_t dev);
   72 static int at91_spi_attach(device_t dev);
   73 static int at91_spi_detach(device_t dev);
   74 
   75 /* helper routines */
   76 static int at91_spi_activate(device_t dev);
   77 static void at91_spi_deactivate(device_t dev);
   78 static void at91_spi_intr(void *arg);
   79 
   80 static int
   81 at91_spi_probe(device_t dev)
   82 {
   83         device_set_desc(dev, "SPI");
   84         return (0);
   85 }
   86 
   87 static int
   88 at91_spi_attach(device_t dev)
   89 {
   90         struct at91_spi_softc *sc = device_get_softc(dev);
   91         int err, i;
   92 
   93         sc->dev = dev;
   94         err = at91_spi_activate(dev);
   95         if (err)
   96                 goto out;
   97 
   98         /*
   99          * Allocate DMA tags and maps
  100          */
  101         err = bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0,
  102             BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 2058, 1,
  103             2048, BUS_DMA_ALLOCNOW, NULL, NULL, &sc->dmatag);
  104         if (err != 0)
  105                 goto out;
  106         for (i = 0; i < 4; i++) {
  107                 err = bus_dmamap_create(sc->dmatag, 0,  &sc->map[i]);
  108                 if (err != 0)
  109                         goto out;
  110         }
  111 
  112         // reset the SPI
  113         WR4(sc, SPI_CR, SPI_CR_SWRST);
  114         WR4(sc, SPI_IDR, 0xffffffff);
  115 
  116         WR4(sc, SPI_MR, (0xf << 24) | SPI_MR_MSTR | SPI_MR_MODFDIS |
  117             (0xE << 16));
  118 
  119         WR4(sc, SPI_CSR0, SPI_CSR_CPOL | (4 << 16) | (2 << 8));
  120         WR4(sc, SPI_CR, SPI_CR_SPIEN);
  121 
  122         WR4(sc, PDC_PTCR, PDC_PTCR_TXTDIS);
  123         WR4(sc, PDC_PTCR, PDC_PTCR_RXTDIS);
  124         WR4(sc, PDC_RNPR, 0);
  125         WR4(sc, PDC_RNCR, 0);
  126         WR4(sc, PDC_TNPR, 0);
  127         WR4(sc, PDC_TNCR, 0);
  128         WR4(sc, PDC_RPR, 0);
  129         WR4(sc, PDC_RCR, 0);
  130         WR4(sc, PDC_TPR, 0);
  131         WR4(sc, PDC_TCR, 0);
  132         RD4(sc, SPI_RDR);
  133         RD4(sc, SPI_SR);
  134 
  135         device_add_child(dev, "spibus", -1);
  136         bus_generic_attach(dev);
  137 out:;
  138         if (err)
  139                 at91_spi_deactivate(dev);
  140         return (err);
  141 }
  142 
  143 static int
  144 at91_spi_detach(device_t dev)
  145 {
  146         return (EBUSY); /* XXX */
  147 }
  148 
  149 static int
  150 at91_spi_activate(device_t dev)
  151 {
  152         struct at91_spi_softc *sc;
  153         int rid, err = ENOMEM;
  154 
  155         sc = device_get_softc(dev);
  156         rid = 0;
  157         sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
  158             RF_ACTIVE);
  159         if (sc->mem_res == NULL)
  160                 goto errout;
  161         rid = 0;
  162         sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
  163             RF_ACTIVE);
  164         if (sc->irq_res == NULL)
  165                 goto errout;
  166         err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
  167             NULL, at91_spi_intr, sc, &sc->intrhand);
  168         if (err != 0)
  169                 goto errout;
  170         return (0);
  171 errout:
  172         at91_spi_deactivate(dev);
  173         return (err);
  174 }
  175 
  176 static void
  177 at91_spi_deactivate(device_t dev)
  178 {
  179         struct at91_spi_softc *sc;
  180 
  181         sc = device_get_softc(dev);
  182         if (sc->intrhand)
  183                 bus_teardown_intr(dev, sc->irq_res, sc->intrhand);
  184         sc->intrhand = 0;
  185         bus_generic_detach(sc->dev);
  186         if (sc->mem_res)
  187                 bus_release_resource(dev, SYS_RES_IOPORT,
  188                     rman_get_rid(sc->mem_res), sc->mem_res);
  189         sc->mem_res = 0;
  190         if (sc->irq_res)
  191                 bus_release_resource(dev, SYS_RES_IRQ,
  192                     rman_get_rid(sc->irq_res), sc->irq_res);
  193         sc->irq_res = 0;
  194         return;
  195 }
  196 
  197 static void
  198 at91_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
  199 {
  200         if (error != 0)
  201                 return;
  202         *(bus_addr_t *)arg = segs[0].ds_addr;
  203 }
  204 
  205 static int
  206 at91_spi_transfer(device_t dev, device_t child, struct spi_command *cmd)
  207 {
  208         struct at91_spi_softc *sc;
  209         int i, j, rxdone, err, mode[4];
  210         bus_addr_t addr;
  211 
  212         sc = device_get_softc(dev);
  213         WR4(sc, PDC_PTCR, PDC_PTCR_TXTDIS | PDC_PTCR_RXTDIS);
  214         i = 0;
  215         if (bus_dmamap_load(sc->dmatag, sc->map[i], cmd->tx_cmd,
  216             cmd->tx_cmd_sz, at91_getaddr, &addr, 0) != 0)
  217                 goto out;
  218         WR4(sc, PDC_TPR, addr);
  219         WR4(sc, PDC_TCR, cmd->tx_cmd_sz);
  220         bus_dmamap_sync(sc->dmatag, sc->map[i], BUS_DMASYNC_PREWRITE);
  221         mode[i++] = BUS_DMASYNC_POSTWRITE;
  222         if (cmd->tx_data_sz > 0) {
  223                 if (bus_dmamap_load(sc->dmatag, sc->map[i], cmd->tx_data,
  224                         cmd->tx_data_sz, at91_getaddr, &addr, 0) != 0)
  225                         goto out;
  226                 WR4(sc, PDC_TNPR, addr);
  227                 WR4(sc, PDC_TNCR, cmd->tx_data_sz);
  228                 bus_dmamap_sync(sc->dmatag, sc->map[i], BUS_DMASYNC_PREWRITE);
  229                 mode[i++] = BUS_DMASYNC_POSTWRITE;
  230         }
  231         if (bus_dmamap_load(sc->dmatag, sc->map[i], cmd->rx_cmd,
  232             cmd->tx_cmd_sz, at91_getaddr, &addr, 0) != 0)
  233                 goto out;
  234         WR4(sc, PDC_RPR, addr);
  235         WR4(sc, PDC_RCR, cmd->tx_cmd_sz);
  236         bus_dmamap_sync(sc->dmatag, sc->map[i], BUS_DMASYNC_PREREAD);
  237         mode[i++] = BUS_DMASYNC_POSTREAD;
  238         if (cmd->rx_data_sz > 0) {
  239                 if (bus_dmamap_load(sc->dmatag, sc->map[i], cmd->rx_data,
  240                         cmd->tx_data_sz, at91_getaddr, &addr, 0) != 0)
  241                         goto out;
  242                 WR4(sc, PDC_RNPR, addr);
  243                 WR4(sc, PDC_RNCR, cmd->rx_data_sz);
  244                 bus_dmamap_sync(sc->dmatag, sc->map[i], BUS_DMASYNC_PREREAD);
  245                 mode[i++] = BUS_DMASYNC_POSTREAD;
  246         }
  247         WR4(sc, SPI_IER, SPI_SR_ENDRX);
  248         WR4(sc, PDC_PTCR, PDC_PTCR_TXTEN | PDC_PTCR_RXTEN);
  249 
  250         rxdone = sc->rxdone;
  251         do {
  252                 err = tsleep(&sc->rxdone, PCATCH | PZERO, "spi", hz);
  253         } while (rxdone == sc->rxdone && err != EINTR);
  254         WR4(sc, PDC_PTCR, PDC_PTCR_TXTDIS | PDC_PTCR_RXTDIS);
  255         if (err == 0) {
  256                 for (j = 0; j < i; j++) 
  257                         bus_dmamap_sync(sc->dmatag, sc->map[j], mode[j]);
  258         }
  259         for (j = 0; j < i; j++)
  260                 bus_dmamap_unload(sc->dmatag, sc->map[j]);
  261         return (err);
  262 out:;
  263         for (j = 0; j < i; j++)
  264                 bus_dmamap_unload(sc->dmatag, sc->map[j]);
  265         return (EIO);
  266 }
  267 
  268 static void
  269 at91_spi_intr(void *arg)
  270 {
  271         struct at91_spi_softc *sc = (struct at91_spi_softc*)arg;
  272         uint32_t sr;
  273 
  274         sr = RD4(sc, SPI_SR) & RD4(sc, SPI_IMR);
  275         if (sr & SPI_SR_ENDRX) {
  276                 sc->rxdone++;
  277                 WR4(sc, SPI_IDR, SPI_SR_ENDRX);
  278                 wakeup(&sc->rxdone);
  279         }
  280         if (sr & ~SPI_SR_ENDRX) {
  281                 device_printf(sc->dev, "Unexpected ISR %#x\n", sr);
  282                 WR4(sc, SPI_IDR, sr & ~SPI_SR_ENDRX);
  283         }
  284 }
  285 
  286 static devclass_t at91_spi_devclass;
  287 
  288 static device_method_t at91_spi_methods[] = {
  289         /* Device interface */
  290         DEVMETHOD(device_probe,         at91_spi_probe),
  291         DEVMETHOD(device_attach,        at91_spi_attach),
  292         DEVMETHOD(device_detach,        at91_spi_detach),
  293 
  294         /* spibus interface */
  295         DEVMETHOD(spibus_transfer,      at91_spi_transfer),
  296         { 0, 0 }
  297 };
  298 
  299 static driver_t at91_spi_driver = {
  300         "spi",
  301         at91_spi_methods,
  302         sizeof(struct at91_spi_softc),
  303 };
  304 
  305 DRIVER_MODULE(at91_spi, atmelarm, at91_spi_driver, at91_spi_devclass, 0, 0);

Cache object: 615d4477befa370a2d7ad82e3dc56ae9


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