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/broadcom/bcm2835/bcm2835_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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org>
    5  * Copyright (c) 2013 Luiz Otavio O Souza <loos@freebsd.org>
    6  * All rights reserved.
    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 AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  *
   29  */
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD$");
   32 
   33 #include <sys/param.h>
   34 #include <sys/systm.h>
   35 #include <sys/bus.h>
   36 
   37 #include <sys/kernel.h>
   38 #include <sys/module.h>
   39 #include <sys/rman.h>
   40 #include <sys/lock.h>
   41 #include <sys/mutex.h>
   42 #include <sys/sysctl.h>
   43 
   44 #include <machine/bus.h>
   45 #include <machine/resource.h>
   46 #include <machine/intr.h>
   47 
   48 #include <dev/ofw/ofw_bus.h>
   49 #include <dev/ofw/ofw_bus_subr.h>
   50 
   51 #include <dev/spibus/spi.h>
   52 #include <dev/spibus/spibusvar.h>
   53 
   54 #include <arm/broadcom/bcm2835/bcm2835_spireg.h>
   55 #include <arm/broadcom/bcm2835/bcm2835_spivar.h>
   56 
   57 #include "spibus_if.h"
   58 
   59 static struct ofw_compat_data compat_data[] = {
   60         {"broadcom,bcm2835-spi",        1},
   61         {"brcm,bcm2835-spi",            1},
   62         {NULL,                          0}
   63 };
   64 
   65 static void bcm_spi_intr(void *);
   66 
   67 #ifdef  BCM_SPI_DEBUG
   68 static void
   69 bcm_spi_printr(device_t dev)
   70 {
   71         struct bcm_spi_softc *sc;
   72         uint32_t reg;
   73 
   74         sc = device_get_softc(dev);
   75         reg = BCM_SPI_READ(sc, SPI_CS);
   76         device_printf(dev, "CS=%b\n", reg,
   77             "\2\1CS0\2CS1\3CPHA\4CPOL\7CSPOL"
   78             "\10TA\11DMAEN\12INTD\13INTR\14ADCS\15REN\16LEN"
   79             "\21DONE\22RXD\23TXD\24RXR\25RXF\26CSPOL0\27CSPOL1"
   80             "\30CSPOL2\31DMA_LEN\32LEN_LONG");
   81         reg = BCM_SPI_READ(sc, SPI_CLK) & SPI_CLK_MASK;
   82         if (reg % 2)
   83                 reg--;
   84         if (reg == 0)
   85                 reg = 65536;
   86         device_printf(dev, "CLK=%uMhz/%d=%luhz\n",
   87             SPI_CORE_CLK / 1000000, reg, SPI_CORE_CLK / reg);
   88         reg = BCM_SPI_READ(sc, SPI_DLEN) & SPI_DLEN_MASK;
   89         device_printf(dev, "DLEN=%d\n", reg);
   90         reg = BCM_SPI_READ(sc, SPI_LTOH) & SPI_LTOH_MASK;
   91         device_printf(dev, "LTOH=%d\n", reg);
   92         reg = BCM_SPI_READ(sc, SPI_DC);
   93         device_printf(dev, "DC=RPANIC=%#x RDREQ=%#x TPANIC=%#x TDREQ=%#x\n",
   94             (reg & SPI_DC_RPANIC_MASK) >> SPI_DC_RPANIC_SHIFT,
   95             (reg & SPI_DC_RDREQ_MASK) >> SPI_DC_RDREQ_SHIFT,
   96             (reg & SPI_DC_TPANIC_MASK) >> SPI_DC_TPANIC_SHIFT,
   97             (reg & SPI_DC_TDREQ_MASK) >> SPI_DC_TDREQ_SHIFT);
   98 }
   99 #endif
  100 
  101 static void
  102 bcm_spi_modifyreg(struct bcm_spi_softc *sc, uint32_t off, uint32_t mask,
  103         uint32_t value)
  104 {
  105         uint32_t reg;
  106 
  107         mtx_assert(&sc->sc_mtx, MA_OWNED);
  108         reg = BCM_SPI_READ(sc, off);
  109         reg &= ~mask;
  110         reg |= value;
  111         BCM_SPI_WRITE(sc, off, reg);
  112 }
  113 
  114 static int
  115 bcm_spi_clock_proc(SYSCTL_HANDLER_ARGS)
  116 {
  117         struct bcm_spi_softc *sc;
  118         uint32_t clk;
  119         int error;
  120 
  121         sc = (struct bcm_spi_softc *)arg1;
  122 
  123         BCM_SPI_LOCK(sc);
  124         clk = BCM_SPI_READ(sc, SPI_CLK);
  125         BCM_SPI_UNLOCK(sc);
  126         clk &= 0xffff;
  127         if (clk == 0)
  128                 clk = 65536;
  129         clk = SPI_CORE_CLK / clk;
  130 
  131         error = sysctl_handle_int(oidp, &clk, sizeof(clk), req);
  132         if (error != 0 || req->newptr == NULL)
  133                 return (error);
  134 
  135         return (0);
  136 }
  137 
  138 static int
  139 bcm_spi_cs_bit_proc(SYSCTL_HANDLER_ARGS, uint32_t bit)
  140 {
  141         struct bcm_spi_softc *sc;
  142         uint32_t reg;
  143         int error;
  144 
  145         sc = (struct bcm_spi_softc *)arg1;
  146         BCM_SPI_LOCK(sc);
  147         reg = BCM_SPI_READ(sc, SPI_CS);
  148         BCM_SPI_UNLOCK(sc);
  149         reg = (reg & bit) ? 1 : 0;
  150 
  151         error = sysctl_handle_int(oidp, &reg, sizeof(reg), req);
  152         if (error != 0 || req->newptr == NULL)
  153                 return (error);
  154 
  155         return (0);
  156 }
  157 
  158 static int
  159 bcm_spi_cpol_proc(SYSCTL_HANDLER_ARGS)
  160 {
  161 
  162         return (bcm_spi_cs_bit_proc(oidp, arg1, arg2, req, SPI_CS_CPOL));
  163 }
  164 
  165 static int
  166 bcm_spi_cpha_proc(SYSCTL_HANDLER_ARGS)
  167 {
  168 
  169         return (bcm_spi_cs_bit_proc(oidp, arg1, arg2, req, SPI_CS_CPHA));
  170 }
  171 
  172 static int
  173 bcm_spi_cspol0_proc(SYSCTL_HANDLER_ARGS)
  174 {
  175 
  176         return (bcm_spi_cs_bit_proc(oidp, arg1, arg2, req, SPI_CS_CSPOL0));
  177 }
  178 
  179 static int
  180 bcm_spi_cspol1_proc(SYSCTL_HANDLER_ARGS)
  181 {
  182 
  183         return (bcm_spi_cs_bit_proc(oidp, arg1, arg2, req, SPI_CS_CSPOL1));
  184 }
  185 
  186 static int
  187 bcm_spi_cspol2_proc(SYSCTL_HANDLER_ARGS)
  188 {
  189 
  190         return (bcm_spi_cs_bit_proc(oidp, arg1, arg2, req, SPI_CS_CSPOL2));
  191 }
  192 
  193 static void
  194 bcm_spi_sysctl_init(struct bcm_spi_softc *sc)
  195 {
  196         struct sysctl_ctx_list *ctx;
  197         struct sysctl_oid *tree_node;
  198         struct sysctl_oid_list *tree;
  199 
  200         /*
  201          * Add system sysctl tree/handlers.
  202          */
  203         ctx = device_get_sysctl_ctx(sc->sc_dev);
  204         tree_node = device_get_sysctl_tree(sc->sc_dev);
  205         tree = SYSCTL_CHILDREN(tree_node);
  206         SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "clock",
  207             CTLFLAG_RD | CTLTYPE_UINT | CTLFLAG_NEEDGIANT, sc, sizeof(*sc),
  208             bcm_spi_clock_proc, "IU", "SPI BUS clock frequency");
  209         SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "cpol",
  210             CTLFLAG_RD | CTLTYPE_UINT | CTLFLAG_NEEDGIANT, sc, sizeof(*sc),
  211             bcm_spi_cpol_proc, "IU", "SPI BUS clock polarity");
  212         SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "cpha",
  213             CTLFLAG_RD | CTLTYPE_UINT | CTLFLAG_NEEDGIANT, sc, sizeof(*sc),
  214             bcm_spi_cpha_proc, "IU", "SPI BUS clock phase");
  215         SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "cspol0",
  216             CTLFLAG_RD | CTLTYPE_UINT | CTLFLAG_NEEDGIANT, sc, sizeof(*sc),
  217             bcm_spi_cspol0_proc, "IU", "SPI BUS chip select 0 polarity");
  218         SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "cspol1",
  219             CTLFLAG_RD | CTLTYPE_UINT | CTLFLAG_NEEDGIANT, sc, sizeof(*sc),
  220             bcm_spi_cspol1_proc, "IU", "SPI BUS chip select 1 polarity");
  221         SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "cspol2",
  222             CTLFLAG_RD | CTLTYPE_UINT | CTLFLAG_NEEDGIANT, sc, sizeof(*sc),
  223             bcm_spi_cspol2_proc, "IU", "SPI BUS chip select 2 polarity");
  224 }
  225 
  226 static int
  227 bcm_spi_probe(device_t dev)
  228 {
  229 
  230         if (!ofw_bus_status_okay(dev))
  231                 return (ENXIO);
  232 
  233         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
  234                 return (ENXIO);
  235 
  236         device_set_desc(dev, "BCM2708/2835 SPI controller");
  237 
  238         return (BUS_PROBE_DEFAULT);
  239 }
  240 
  241 static int
  242 bcm_spi_attach(device_t dev)
  243 {
  244         struct bcm_spi_softc *sc;
  245         int rid;
  246 
  247         if (device_get_unit(dev) != 0) {
  248                 device_printf(dev, "only one SPI controller supported\n");
  249                 return (ENXIO);
  250         }
  251 
  252         sc = device_get_softc(dev);
  253         sc->sc_dev = dev;
  254 
  255         rid = 0;
  256         sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
  257             RF_ACTIVE);
  258         if (!sc->sc_mem_res) {
  259                 device_printf(dev, "cannot allocate memory window\n");
  260                 return (ENXIO);
  261         }
  262 
  263         sc->sc_bst = rman_get_bustag(sc->sc_mem_res);
  264         sc->sc_bsh = rman_get_bushandle(sc->sc_mem_res);
  265 
  266         rid = 0;
  267         sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
  268             RF_ACTIVE);
  269         if (!sc->sc_irq_res) {
  270                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
  271                 device_printf(dev, "cannot allocate interrupt\n");
  272                 return (ENXIO);
  273         }
  274 
  275         /* Hook up our interrupt handler. */
  276         if (bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
  277             NULL, bcm_spi_intr, sc, &sc->sc_intrhand)) {
  278                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res);
  279                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
  280                 device_printf(dev, "cannot setup the interrupt handler\n");
  281                 return (ENXIO);
  282         }
  283 
  284         mtx_init(&sc->sc_mtx, "bcm_spi", NULL, MTX_DEF);
  285 
  286         /* Add sysctl nodes. */
  287         bcm_spi_sysctl_init(sc);
  288 
  289 #ifdef  BCM_SPI_DEBUG
  290         bcm_spi_printr(dev);
  291 #endif
  292 
  293         /*
  294          * Enable the SPI controller.  Clear the rx and tx FIFO.
  295          * Defaults to SPI mode 0.
  296          */
  297         BCM_SPI_WRITE(sc, SPI_CS, SPI_CS_CLEAR_RXFIFO | SPI_CS_CLEAR_TXFIFO);
  298 
  299 #ifdef  BCM_SPI_DEBUG
  300         bcm_spi_printr(dev);
  301 #endif
  302 
  303         device_add_child(dev, "spibus", -1);
  304 
  305         return (bus_generic_attach(dev));
  306 }
  307 
  308 static int
  309 bcm_spi_detach(device_t dev)
  310 {
  311         struct bcm_spi_softc *sc;
  312 
  313         bus_generic_detach(dev);
  314 
  315         sc = device_get_softc(dev);
  316         mtx_destroy(&sc->sc_mtx);
  317         if (sc->sc_intrhand)
  318                 bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intrhand);
  319         if (sc->sc_irq_res)
  320                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res);
  321         if (sc->sc_mem_res)
  322                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
  323 
  324         return (0);
  325 }
  326 
  327 static void
  328 bcm_spi_fill_fifo(struct bcm_spi_softc *sc)
  329 {
  330         struct spi_command *cmd;
  331         uint32_t cs, written;
  332         uint8_t *data;
  333 
  334         cmd = sc->sc_cmd;
  335         cs = BCM_SPI_READ(sc, SPI_CS) & (SPI_CS_TA | SPI_CS_TXD);
  336         while (sc->sc_written < sc->sc_len &&
  337             cs == (SPI_CS_TA | SPI_CS_TXD)) {
  338                 data = (uint8_t *)cmd->tx_cmd;
  339                 written = sc->sc_written++;
  340                 if (written >= cmd->tx_cmd_sz) {
  341                         data = (uint8_t *)cmd->tx_data;
  342                         written -= cmd->tx_cmd_sz;
  343                 }
  344                 BCM_SPI_WRITE(sc, SPI_FIFO, data[written]);
  345                 cs = BCM_SPI_READ(sc, SPI_CS) & (SPI_CS_TA | SPI_CS_TXD);
  346         }
  347 }
  348 
  349 static void
  350 bcm_spi_drain_fifo(struct bcm_spi_softc *sc)
  351 {
  352         struct spi_command *cmd;
  353         uint32_t cs, read;
  354         uint8_t *data;
  355 
  356         cmd = sc->sc_cmd;
  357         cs = BCM_SPI_READ(sc, SPI_CS) & SPI_CS_RXD;
  358         while (sc->sc_read < sc->sc_len && cs == SPI_CS_RXD) {
  359                 data = (uint8_t *)cmd->rx_cmd;
  360                 read = sc->sc_read++;
  361                 if (read >= cmd->rx_cmd_sz) {
  362                         data = (uint8_t *)cmd->rx_data;
  363                         read -= cmd->rx_cmd_sz;
  364                 }
  365                 data[read] = BCM_SPI_READ(sc, SPI_FIFO) & 0xff;
  366                 cs = BCM_SPI_READ(sc, SPI_CS) & SPI_CS_RXD;
  367         }
  368 }
  369 
  370 static void
  371 bcm_spi_intr(void *arg)
  372 {
  373         struct bcm_spi_softc *sc;
  374 
  375         sc = (struct bcm_spi_softc *)arg;
  376         BCM_SPI_LOCK(sc);
  377 
  378         /* Filter stray interrupts. */
  379         if ((sc->sc_flags & BCM_SPI_BUSY) == 0) {
  380                 BCM_SPI_UNLOCK(sc);
  381                 return;
  382         }
  383 
  384         /* TX - Fill up the FIFO. */
  385         bcm_spi_fill_fifo(sc);
  386 
  387         /* RX - Drain the FIFO. */
  388         bcm_spi_drain_fifo(sc);
  389 
  390         /* Check for end of transfer. */
  391         if (sc->sc_written == sc->sc_len && sc->sc_read == sc->sc_len) {
  392                 /* Disable interrupts and the SPI engine. */
  393                 bcm_spi_modifyreg(sc, SPI_CS,
  394                     SPI_CS_TA | SPI_CS_INTR | SPI_CS_INTD, 0);
  395                 wakeup(sc->sc_dev);
  396         }
  397 
  398         BCM_SPI_UNLOCK(sc);
  399 }
  400 
  401 static int
  402 bcm_spi_transfer(device_t dev, device_t child, struct spi_command *cmd)
  403 {
  404         struct bcm_spi_softc *sc;
  405         uint32_t cs, mode, clock;
  406         int err;
  407 
  408         sc = device_get_softc(dev);
  409 
  410         KASSERT(cmd->tx_cmd_sz == cmd->rx_cmd_sz, 
  411             ("TX/RX command sizes should be equal"));
  412         KASSERT(cmd->tx_data_sz == cmd->rx_data_sz, 
  413             ("TX/RX data sizes should be equal"));
  414 
  415         /* Get the bus speed, mode, and chip select for this child. */
  416 
  417         spibus_get_cs(child, &cs);
  418         if ((cs & (~SPIBUS_CS_HIGH)) > 2) {
  419                 device_printf(dev,
  420                     "Invalid chip select %u requested by %s\n", cs,
  421                     device_get_nameunit(child));
  422                 return (EINVAL);
  423         }
  424 
  425         spibus_get_clock(child, &clock);
  426         if (clock == 0) {
  427                 device_printf(dev,
  428                     "Invalid clock %uHz requested by %s\n", clock,
  429                     device_get_nameunit(child));
  430                 return (EINVAL);
  431         }
  432 
  433         spibus_get_mode(child, &mode);
  434         if (mode > 3) {
  435                 device_printf(dev,
  436                     "Invalid mode %u requested by %s\n", mode,
  437                     device_get_nameunit(child));
  438                 return (EINVAL);
  439         }
  440 
  441         /* If the controller is in use wait until it is available. */
  442         BCM_SPI_LOCK(sc);
  443         while (sc->sc_flags & BCM_SPI_BUSY)
  444                 mtx_sleep(dev, &sc->sc_mtx, 0, "bcm_spi", 0);
  445 
  446         /* Now we have control over SPI controller. */
  447         sc->sc_flags = BCM_SPI_BUSY;
  448 
  449         /* Clear the FIFO. */
  450         bcm_spi_modifyreg(sc, SPI_CS,
  451             SPI_CS_CLEAR_RXFIFO | SPI_CS_CLEAR_TXFIFO,
  452             SPI_CS_CLEAR_RXFIFO | SPI_CS_CLEAR_TXFIFO);
  453 
  454         /* Save a pointer to the SPI command. */
  455         sc->sc_cmd = cmd;
  456         sc->sc_read = 0;
  457         sc->sc_written = 0;
  458         sc->sc_len = cmd->tx_cmd_sz + cmd->tx_data_sz;
  459 
  460 #ifdef  BCM2835_SPI_USE_CS_HIGH /* TODO: for when behavior is correct */
  461         /*
  462          * Assign CS polarity first, while the CS indicates 'inactive'.
  463          * This will need to set the correct polarity bit based on the 'cs', and
  464          * the polarity bit will remain in this state, even after the transaction
  465          * is complete.
  466          */
  467         if((cs & ~SPIBUS_CS_HIGH) == 0) {
  468                 bcm_spi_modifyreg(sc, SPI_CS,
  469                     SPI_CS_CSPOL0,
  470                     ((cs & (SPIBUS_CS_HIGH)) ? SPI_CS_CSPOL0 : 0));
  471         }
  472         else if((cs & ~SPIBUS_CS_HIGH) == 1) {
  473                 bcm_spi_modifyreg(sc, SPI_CS,
  474                     SPI_CS_CSPOL1,
  475                     ((cs & (SPIBUS_CS_HIGH)) ? SPI_CS_CSPOL1 : 0));
  476         }
  477         else if((cs & ~SPIBUS_CS_HIGH) == 2) {
  478                 bcm_spi_modifyreg(sc, SPI_CS,
  479                     SPI_CS_CSPOL2,
  480                     ((cs & (SPIBUS_CS_HIGH)) ? SPI_CS_CSPOL2 : 0));
  481         }
  482 #endif
  483 
  484         /*
  485          * Set the mode in 'SPI_CS' (clock phase and polarity bits).
  486          * This must happen before CS output pin is active.
  487          * Otherwise, you might glitch and drop the first bit.
  488          */
  489         bcm_spi_modifyreg(sc, SPI_CS,
  490             SPI_CS_CPOL | SPI_CS_CPHA,
  491             ((mode & SPIBUS_MODE_CPHA) ? SPI_CS_CPHA : 0) |
  492             ((mode & SPIBUS_MODE_CPOL) ? SPI_CS_CPOL : 0));
  493 
  494         /*
  495          * Set the clock divider in 'SPI_CLK - see 'bcm_spi_clock_proc()'.
  496          */
  497 
  498         /* calculate 'clock' as a divider value from freq */
  499         clock = SPI_CORE_CLK / clock;
  500         if (clock <= 1)
  501                 clock = 2;
  502         else if (clock % 2)
  503                 clock--;
  504         if (clock > 0xffff)
  505                 clock = 0;
  506 
  507         BCM_SPI_WRITE(sc, SPI_CLK, clock);
  508 
  509         /*
  510          * Set the CS for this transaction, enable interrupts and announce
  511          * we're ready to tx.  This will kick off the first interrupt.
  512          */
  513         bcm_spi_modifyreg(sc, SPI_CS,
  514             SPI_CS_MASK | SPI_CS_TA | SPI_CS_INTR | SPI_CS_INTD,
  515             (cs & (~SPIBUS_CS_HIGH)) | /* cs is the lower 2 bits of the reg */
  516             SPI_CS_TA | SPI_CS_INTR | SPI_CS_INTD);
  517 
  518         /* Wait for the transaction to complete. */
  519         err = mtx_sleep(dev, &sc->sc_mtx, 0, "bcm_spi", hz * 2);
  520 
  521         /* Make sure the SPI engine and interrupts are disabled. */
  522         bcm_spi_modifyreg(sc, SPI_CS, SPI_CS_TA | SPI_CS_INTR | SPI_CS_INTD, 0);
  523 
  524         /* Release the controller and wakeup the next thread waiting for it. */
  525         sc->sc_flags = 0;
  526         wakeup_one(dev);
  527         BCM_SPI_UNLOCK(sc);
  528 
  529         /*
  530          * Check for transfer timeout.  The SPI controller doesn't
  531          * return errors.
  532          */
  533         if (err == EWOULDBLOCK) {
  534                 device_printf(sc->sc_dev, "SPI error (timeout)\n");
  535                 err = EIO;
  536         }
  537 
  538         return (err);
  539 }
  540 
  541 static phandle_t
  542 bcm_spi_get_node(device_t bus, device_t dev)
  543 {
  544 
  545         /* We only have one child, the SPI bus, which needs our own node. */
  546         return (ofw_bus_get_node(bus));
  547 }
  548 
  549 static device_method_t bcm_spi_methods[] = {
  550         /* Device interface */
  551         DEVMETHOD(device_probe,         bcm_spi_probe),
  552         DEVMETHOD(device_attach,        bcm_spi_attach),
  553         DEVMETHOD(device_detach,        bcm_spi_detach),
  554 
  555         /* SPI interface */
  556         DEVMETHOD(spibus_transfer,      bcm_spi_transfer),
  557 
  558         /* ofw_bus interface */
  559         DEVMETHOD(ofw_bus_get_node,     bcm_spi_get_node),
  560 
  561         DEVMETHOD_END
  562 };
  563 
  564 static driver_t bcm_spi_driver = {
  565         "spi",
  566         bcm_spi_methods,
  567         sizeof(struct bcm_spi_softc),
  568 };
  569 
  570 DRIVER_MODULE(bcm2835_spi, simplebus, bcm_spi_driver, 0, 0);

Cache object: 9e6b5e475195054e41faf570697fc105


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