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/freescale/imx/imx_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) 2018 Ian Lepore <ian@freebsd.org>
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD$");
   31 
   32 /*
   33  * Driver for imx Enhanced Configurable SPI; master-mode only.
   34  */
   35 
   36 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/bus.h>
   39 #include <sys/gpio.h>
   40 #include <sys/kernel.h>
   41 #include <sys/lock.h>
   42 #include <sys/module.h>
   43 #include <sys/mutex.h>
   44 #include <sys/rman.h>
   45 #include <sys/sysctl.h>
   46 #include <machine/bus.h>
   47 #include <machine/cpu.h>
   48 #include <machine/intr.h>
   49 
   50 #include <arm/freescale/imx/imx_ccmvar.h>
   51 
   52 #include <dev/gpio/gpiobusvar.h>
   53 #include <dev/ofw/ofw_bus.h>
   54 #include <dev/ofw/ofw_bus_subr.h>
   55 #include <dev/ofw/openfirm.h>
   56 #include <dev/spibus/spi.h>
   57 #include <dev/spibus/spibusvar.h>
   58 
   59 #include "spibus_if.h"
   60 
   61 #define ECSPI_RXDATA            0x00
   62 #define ECSPI_TXDATA            0x04
   63 #define ECSPI_CTLREG            0x08
   64 #define   CTLREG_BLEN_SHIFT       20
   65 #define   CTLREG_BLEN_MASK        0x0fff
   66 #define   CTLREG_CSEL_SHIFT       18
   67 #define   CTLREG_CSEL_MASK        0x03
   68 #define   CTLREG_DRCTL_SHIFT      16
   69 #define   CTLREG_DRCTL_MASK       0x03
   70 #define   CTLREG_PREDIV_SHIFT     12
   71 #define   CTLREG_PREDIV_MASK      0x0f
   72 #define   CTLREG_POSTDIV_SHIFT    8
   73 #define   CTLREG_POSTDIV_MASK     0x0f
   74 #define   CTLREG_CMODE_SHIFT      4
   75 #define   CTLREG_CMODE_MASK       0x0f
   76 #define   CTLREG_CMODES_MASTER    (CTLREG_CMODE_MASK << CTLREG_CMODE_SHIFT)
   77 #define   CTLREG_SMC              (1u << 3)
   78 #define   CTLREG_XCH              (1u << 2)
   79 #define   CTLREG_HT               (1u << 1)
   80 #define   CTLREG_EN               (1u << 0)
   81 #define ECSPI_CFGREG            0x0c
   82 #define   CFGREG_HTLEN_SHIFT      24
   83 #define   CFGREG_SCLKCTL_SHIFT    20
   84 #define   CFGREG_DATACTL_SHIFT    16
   85 #define   CFGREG_SSPOL_SHIFT      12
   86 #define   CFGREG_SSCTL_SHIFT       8
   87 #define   CFGREG_SCLKPOL_SHIFT     4 
   88 #define   CFGREG_SCLKPHA_SHIFT     0
   89 #define   CFGREG_MASK              0x0f /* all CFGREG fields are 4 bits */
   90 #define ECSPI_INTREG            0x10
   91 #define   INTREG_TCEN             (1u << 7)
   92 #define   INTREG_ROEN             (1u << 6)
   93 #define   INTREG_RFEN             (1u << 5)
   94 #define   INTREG_RDREN            (1u << 4)
   95 #define   INTREG_RREN             (1u << 3)
   96 #define   INTREG_TFEN             (1u << 2)
   97 #define   INTREG_TDREN            (1u << 1)
   98 #define   INTREG_TEEN             (1u << 0)
   99 #define ECSPI_DMAREG            0x14
  100 #define   DMA_RX_THRESH_SHIFT     16
  101 #define   DMA_RX_THRESH_MASK      0x3f
  102 #define   DMA_TX_THRESH_SHIFT     0
  103 #define   DMA_TX_THRESH_MASK      0x3f
  104 #define ECSPI_STATREG           0x18
  105 #define   SREG_TC                 (1u << 7)
  106 #define   SREG_RO                 (1u << 6)
  107 #define   SREG_RF                 (1u << 5)
  108 #define   SREG_RDR                (1u << 4)
  109 #define   SREG_RR                 (1u << 3)
  110 #define   SREG_TF                 (1u << 2)
  111 #define   SREG_TDR                (1u << 1)
  112 #define   SREG_TE                 (1u << 0)
  113 #define ECSPI_PERIODREG         0x1c
  114 #define ECSPI_TESTREG           0x20
  115 
  116 #define CS_MAX          4       /* Max number of chip selects. */
  117 #define CS_MASK         0x03    /* Mask flag bits out of chipsel. */
  118 
  119 #define FIFO_SIZE       64
  120 #define FIFO_RXTHRESH   32
  121 #define FIFO_TXTHRESH   32
  122 
  123 struct spi_softc {
  124         device_t                dev;
  125         device_t                spibus;
  126         struct mtx              mtx;
  127         struct resource         *memres;
  128         struct resource         *intres;
  129         void                    *inthandle;
  130         gpio_pin_t              cspins[CS_MAX];
  131         u_int                   debug;
  132         u_int                   basefreq;
  133         uint32_t                ctlreg;
  134         uint32_t                intreg;
  135         uint32_t                fifocnt;
  136         uint8_t                 *rxbuf;
  137         uint32_t                rxidx;
  138         uint32_t                rxlen;
  139         uint8_t                 *txbuf;
  140         uint32_t                txidx;
  141         uint32_t                txlen;
  142 };
  143 
  144 static struct ofw_compat_data compat_data[] = {
  145         {"fsl,imx51-ecspi",  true},
  146         {"fsl,imx53-ecspi",  true},
  147         {"fsl,imx6dl-ecspi", true},
  148         {"fsl,imx6q-ecspi",  true},
  149         {"fsl,imx6sx-ecspi", true},
  150         {"fsl,imx6ul-ecspi", true},
  151         {NULL,               false}
  152 };
  153 
  154 static inline uint32_t
  155 RD4(struct spi_softc *sc, bus_size_t offset)
  156 {
  157 
  158         return (bus_read_4(sc->memres, offset));
  159 }
  160 
  161 static inline void
  162 WR4(struct spi_softc *sc, bus_size_t offset, uint32_t value)
  163 {
  164 
  165         bus_write_4(sc->memres, offset, value);
  166 }
  167 
  168 static u_int
  169 spi_calc_clockdiv(struct spi_softc *sc, u_int busfreq)
  170 {
  171         u_int post, pre;
  172 
  173         /* Returning 0 effectively sets both dividers to 1. */
  174         if (sc->basefreq <= busfreq)
  175                 return (0);
  176 
  177         /*
  178          * Brute-force this; all real-world bus speeds are going to be found on
  179          * the 1st or 2nd time through this loop.
  180          */
  181         for (post = 0; post < 16; ++post) {
  182                 pre = ((sc->basefreq >> post) / busfreq) - 1;
  183                 if (pre < 16)
  184                         break;
  185         }
  186         if (post == 16) {
  187                 /* The lowest we can go is ~115 Hz. */
  188                 pre = 15;
  189                 post = 15;
  190         }
  191 
  192         if (sc->debug >= 2) {
  193                 device_printf(sc->dev,
  194                     "base %u bus %u; pre %u, post %u; actual busfreq %u\n",
  195                     sc->basefreq, busfreq, pre, post,
  196                     (sc->basefreq / (pre + 1)) / (1 << post));
  197         }
  198 
  199         return (pre << CTLREG_PREDIV_SHIFT) | (post << CTLREG_POSTDIV_SHIFT);
  200 }
  201 
  202 static void
  203 spi_set_chipsel(struct spi_softc *sc, u_int cs, bool active)
  204 {
  205         bool pinactive;
  206 
  207         /*
  208          * This is kinda crazy... the gpio pins for chipsel are defined as
  209          * active-high in the dts, but are supposed to be treated as active-low
  210          * by this driver.  So to turn on chipsel we have to invert the value
  211          * passed to gpio_pin_set_active().  Then, to make it more fun, any
  212          * slave can say its chipsel is active-high, so if that option is
  213          * on, we have to invert the value again.
  214          */
  215         pinactive = !active ^ (bool)(cs & SPIBUS_CS_HIGH);
  216 
  217         if (sc->debug >= 2) {
  218                 device_printf(sc->dev, "chipsel %u changed to %u\n",
  219                     (cs & ~SPIBUS_CS_HIGH), pinactive);
  220         }
  221 
  222         /*
  223          * Change the pin, then do a dummy read of its current state to ensure
  224          * that the state change reaches the hardware before proceeding.
  225          */
  226         gpio_pin_set_active(sc->cspins[cs & ~SPIBUS_CS_HIGH], pinactive);
  227         gpio_pin_is_active(sc->cspins[cs & ~SPIBUS_CS_HIGH], &pinactive);
  228 }
  229 
  230 static void
  231 spi_hw_setup(struct spi_softc *sc, u_int cs, u_int mode, u_int freq)
  232 {
  233         uint32_t reg;
  234 
  235         /*
  236          * Set up control register, and write it first to bring the device out
  237          * of reset.
  238          */
  239         sc->ctlreg  = CTLREG_EN | CTLREG_CMODES_MASTER | CTLREG_SMC;
  240         sc->ctlreg |= spi_calc_clockdiv(sc, freq);
  241         sc->ctlreg |= 7 << CTLREG_BLEN_SHIFT; /* XXX byte at a time */
  242         WR4(sc, ECSPI_CTLREG, sc->ctlreg);
  243 
  244         /*
  245          * Set up the config register.  Note that we do all transfers with the
  246          * SPI hardware's chip-select set to zero.  The actual chip select is
  247          * handled with a gpio pin.
  248          */
  249         reg = 0;
  250         if (cs & SPIBUS_CS_HIGH)
  251                 reg |= 1u << CFGREG_SSPOL_SHIFT;
  252         if (mode & SPIBUS_MODE_CPHA)
  253                 reg |= 1u << CFGREG_SCLKPHA_SHIFT;
  254         if (mode & SPIBUS_MODE_CPOL) {
  255                 reg |= 1u << CFGREG_SCLKPOL_SHIFT;
  256                 reg |= 1u << CFGREG_SCLKCTL_SHIFT;
  257         }
  258         WR4(sc, ECSPI_CFGREG, reg);
  259 
  260         /*
  261          * Set up the rx/tx FIFO interrupt thresholds.
  262          */
  263         reg  = (FIFO_RXTHRESH << DMA_RX_THRESH_SHIFT);
  264         reg |= (FIFO_TXTHRESH << DMA_TX_THRESH_SHIFT);
  265         WR4(sc, ECSPI_DMAREG, reg);
  266 
  267         /*
  268          * Do a dummy read, to make sure the preceding writes reach the spi
  269          * hardware before we assert any gpio chip select.
  270          */
  271         (void)RD4(sc, ECSPI_CFGREG);
  272 }
  273 
  274 static void
  275 spi_empty_rxfifo(struct spi_softc *sc)
  276 {
  277 
  278         while (sc->rxidx < sc->rxlen && (RD4(sc, ECSPI_STATREG) & SREG_RR)) {
  279                 sc->rxbuf[sc->rxidx++] = (uint8_t)RD4(sc, ECSPI_RXDATA);
  280                 --sc->fifocnt;
  281         }
  282 }
  283 
  284 static void
  285 spi_fill_txfifo(struct spi_softc *sc)
  286 {
  287 
  288         while (sc->txidx < sc->txlen && sc->fifocnt < FIFO_SIZE) {
  289                 WR4(sc, ECSPI_TXDATA, sc->txbuf[sc->txidx++]);
  290                 ++sc->fifocnt;
  291         }
  292 
  293         /*
  294          * If we're out of data, disable tx data ready (threshold) interrupts,
  295          * and enable tx fifo empty interrupts.
  296          */
  297         if (sc->txidx == sc->txlen)
  298                 sc->intreg = (sc->intreg & ~INTREG_TDREN) | INTREG_TEEN;
  299 }
  300 
  301 static void
  302 spi_intr(void *arg)
  303 {
  304         struct spi_softc *sc = arg;
  305         uint32_t intreg, status;
  306 
  307         mtx_lock(&sc->mtx);
  308 
  309         sc = arg;
  310         intreg = sc->intreg;
  311         status = RD4(sc, ECSPI_STATREG);
  312         WR4(sc, ECSPI_STATREG, status); /* Clear w1c bits. */
  313 
  314         /*
  315          * If we get an overflow error, just signal that the transfer is done
  316          * and wakeup the waiting thread, which will see that txidx != txlen and
  317          * return an IO error to the caller.
  318          */
  319         if (__predict_false(status & SREG_RO)) {
  320                 if (sc->debug || bootverbose) {
  321                         device_printf(sc->dev, "rxoverflow rxidx %u txidx %u\n",
  322                             sc->rxidx, sc->txidx);
  323                 }
  324                 sc->intreg = 0;
  325                 wakeup(sc);
  326                 mtx_unlock(&sc->mtx);
  327                 return;
  328         }
  329 
  330         if (status & SREG_RR)
  331                 spi_empty_rxfifo(sc);
  332 
  333         if (status & SREG_TDR)
  334                 spi_fill_txfifo(sc);
  335 
  336         /*
  337          * If we're out of bytes to send...
  338          *  - If Transfer Complete is set (shift register is empty) and we've
  339          *    received everything we expect, we're all done.
  340          *  - Else if Tx Fifo Empty is set, we need to stop waiting for that and
  341          *    switch to waiting for Transfer Complete (wait for shift register
  342          *    to empty out), and also for Receive Ready (last of incoming data).
  343          */
  344         if (sc->txidx == sc->txlen) {
  345                 if ((status & SREG_TC) && sc->fifocnt == 0) {
  346                         sc->intreg = 0;
  347                         wakeup(sc);
  348                 } else if (status & SREG_TE) {
  349                         sc->intreg &= ~(sc->intreg & ~INTREG_TEEN);
  350                         sc->intreg |= INTREG_TCEN | INTREG_RREN;
  351                 }
  352         }
  353 
  354         /*
  355          * If interrupt flags changed, write the new flags to the hardware and
  356          * do a dummy readback to ensure the changes reach the hardware before
  357          * we exit the isr.
  358          */
  359         if (sc->intreg != intreg) {
  360                 WR4(sc, ECSPI_INTREG, sc->intreg);
  361                 (void)RD4(sc, ECSPI_INTREG);
  362         }
  363 
  364         if (sc->debug >= 3) {
  365                 device_printf(sc->dev,
  366                     "spi_intr, sreg 0x%08x intreg was 0x%08x now 0x%08x\n",
  367                     status, intreg, sc->intreg);
  368         }
  369 
  370         mtx_unlock(&sc->mtx);
  371 }
  372 
  373 static int
  374 spi_xfer_buf(struct spi_softc *sc, void *rxbuf, void *txbuf, uint32_t len)
  375 {
  376         int err;
  377 
  378         if (sc->debug >= 1) {
  379                 device_printf(sc->dev,
  380                     "spi_xfer_buf, rxbuf %p txbuf %p len %u\n",
  381                     rxbuf, txbuf, len);
  382         }
  383 
  384         if (len == 0)
  385                 return (0);
  386 
  387         sc->rxbuf = rxbuf;
  388         sc->rxlen = len;
  389         sc->rxidx = 0;
  390         sc->txbuf = txbuf;
  391         sc->txlen = len;
  392         sc->txidx = 0;
  393         sc->intreg = INTREG_RDREN | INTREG_TDREN;
  394         spi_fill_txfifo(sc);
  395 
  396         /* Enable interrupts last; spi_fill_txfifo() can change sc->intreg */
  397         WR4(sc, ECSPI_INTREG, sc->intreg);
  398 
  399         err = 0;
  400         while (err == 0 && sc->intreg != 0)
  401                 err = msleep(sc, &sc->mtx, 0, "imxspi", 10 * hz);
  402 
  403         if (sc->rxidx != sc->rxlen || sc->txidx != sc->txlen)
  404                 err = EIO;
  405 
  406         return (err);
  407 }
  408 
  409 static int
  410 spi_transfer(device_t dev, device_t child, struct spi_command *cmd)
  411 {
  412         struct spi_softc *sc = device_get_softc(dev);
  413         uint32_t cs, mode, clock;
  414         int err;
  415 
  416         spibus_get_cs(child, &cs);
  417         spibus_get_clock(child, &clock);
  418         spibus_get_mode(child, &mode);
  419 
  420         if (cs > CS_MAX || sc->cspins[cs] == NULL) {
  421                 if (sc->debug || bootverbose)
  422                         device_printf(sc->dev, "Invalid chip select %u\n", cs);
  423                 return (EINVAL);
  424         }
  425 
  426         mtx_lock(&sc->mtx);
  427         device_busy(sc->dev);
  428 
  429         if (sc->debug >= 1) {
  430                 device_printf(sc->dev,
  431                     "spi_transfer, cs 0x%x clock %u mode %u\n",
  432                     cs, clock, mode);
  433         }
  434 
  435         /* Set up the hardware and select the device. */
  436         spi_hw_setup(sc, cs, mode, clock);
  437         spi_set_chipsel(sc, cs, true);
  438 
  439         /* Transfer command then data bytes. */
  440         err = 0;
  441         if (cmd->tx_cmd_sz > 0)
  442                 err = spi_xfer_buf(sc, cmd->rx_cmd, cmd->tx_cmd,
  443                     cmd->tx_cmd_sz);
  444         if (cmd->tx_data_sz > 0 && err == 0)
  445                 err = spi_xfer_buf(sc, cmd->rx_data, cmd->tx_data,
  446                     cmd->tx_data_sz);
  447 
  448         /* Deselect the device, turn off (and reset) hardware. */
  449         spi_set_chipsel(sc, cs, false);
  450         WR4(sc, ECSPI_CTLREG, 0);
  451 
  452         device_unbusy(sc->dev);
  453         mtx_unlock(&sc->mtx);
  454 
  455         return (err);
  456 }
  457 
  458 static phandle_t
  459 spi_get_node(device_t bus, device_t dev)
  460 {
  461 
  462         /*
  463          * Share our controller node with our spibus child; it instantiates
  464          * devices by walking the children contained within our node.
  465          */
  466         return ofw_bus_get_node(bus);
  467 }
  468 
  469 static int
  470 spi_detach(device_t dev)
  471 {
  472         struct spi_softc *sc = device_get_softc(dev);
  473         int error, idx;
  474 
  475         if ((error = bus_generic_detach(sc->dev)) != 0)
  476                 return (error);
  477 
  478         if (sc->spibus != NULL)
  479                 device_delete_child(dev, sc->spibus);
  480 
  481         for (idx = 0; idx < nitems(sc->cspins); ++idx) {
  482                 if (sc->cspins[idx] != NULL)
  483                         gpio_pin_release(sc->cspins[idx]);
  484         }
  485 
  486         if (sc->inthandle != NULL)
  487                 bus_teardown_intr(sc->dev, sc->intres, sc->inthandle);
  488         if (sc->intres != NULL)
  489                 bus_release_resource(sc->dev, SYS_RES_IRQ, 0, sc->intres);
  490         if (sc->memres != NULL)
  491                 bus_release_resource(sc->dev, SYS_RES_MEMORY, 0, sc->memres);
  492 
  493         mtx_destroy(&sc->mtx);
  494 
  495         return (0);
  496 }
  497 
  498 static int
  499 spi_attach(device_t dev)
  500 {
  501         struct spi_softc *sc = device_get_softc(dev);
  502         phandle_t node;
  503         int err, idx, rid;
  504 
  505         sc->dev = dev;
  506         sc->basefreq = imx_ccm_ecspi_hz();
  507 
  508         mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
  509 
  510         /* Set up debug-enable sysctl. */
  511         SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->dev), 
  512             SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)),
  513             OID_AUTO, "debug", CTLFLAG_RWTUN, &sc->debug, 0,
  514             "Enable debug, higher values = more info");
  515 
  516         /* Allocate mmio register access resources. */
  517         rid = 0;
  518         sc->memres = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, &rid,
  519             RF_ACTIVE);
  520         if (sc->memres == NULL) {
  521                 device_printf(sc->dev, "could not allocate registers\n");
  522                 spi_detach(sc->dev);
  523                 return (ENXIO);
  524         }
  525 
  526         /* Allocate interrupt resources and set up handler. */
  527         rid = 0;
  528         sc->intres = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &rid,
  529             RF_ACTIVE);
  530         if (sc->intres == NULL) {
  531                 device_printf(sc->dev, "could not allocate interrupt\n");
  532                 device_detach(sc->dev);
  533                 return (ENXIO);
  534         }
  535         err = bus_setup_intr(sc->dev, sc->intres, INTR_TYPE_MISC | INTR_MPSAFE,
  536             NULL, spi_intr, sc, &sc->inthandle);
  537         if (err != 0) {
  538                 device_printf(sc->dev, "could not setup interrupt handler");
  539                 device_detach(sc->dev);
  540                 return (ENXIO);
  541         }
  542 
  543         /* Allocate gpio pins for configured chip selects. */
  544         node = ofw_bus_get_node(sc->dev);
  545         for (idx = 0; idx < nitems(sc->cspins); ++idx) {
  546                 err = gpio_pin_get_by_ofw_propidx(sc->dev, node, "cs-gpios",
  547                     idx, &sc->cspins[idx]);
  548                 if (err == 0) {
  549                         gpio_pin_setflags(sc->cspins[idx], GPIO_PIN_OUTPUT);
  550                 } else if (sc->debug >= 2) {
  551                         device_printf(sc->dev,
  552                             "cannot configure gpio for chip select %u\n", idx);
  553                 }
  554         }
  555 
  556         /*
  557          * Hardware init: put all channels into Master mode, turn off the enable
  558          * bit (gates off clocks); we only enable the hardware while xfers run.
  559          */
  560         WR4(sc, ECSPI_CTLREG, CTLREG_CMODES_MASTER);
  561 
  562         /*
  563          * Add the spibus driver as a child, and setup a one-shot intrhook to
  564          * attach it after interrupts are working.  It will attach actual SPI
  565          * devices as its children, and those devices may need to do IO during
  566          * their attach. We can't do IO until timers and interrupts are working.
  567          */
  568         sc->spibus = device_add_child(dev, "spibus", -1);
  569         return (bus_delayed_attach_children(dev));
  570 }
  571 
  572 static int
  573 spi_probe(device_t dev)
  574 {
  575 
  576         if (!ofw_bus_status_okay(dev))
  577                 return (ENXIO);
  578 
  579         if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
  580                 return (ENXIO);
  581 
  582         device_set_desc(dev, "i.MX ECSPI Master");
  583         return (BUS_PROBE_DEFAULT);
  584 }
  585 
  586 static device_method_t spi_methods[] = {
  587         DEVMETHOD(device_probe,         spi_probe),
  588         DEVMETHOD(device_attach,        spi_attach),
  589         DEVMETHOD(device_detach,        spi_detach),
  590 
  591         /* spibus_if  */
  592         DEVMETHOD(spibus_transfer,      spi_transfer),
  593 
  594         /* ofw_bus_if */
  595         DEVMETHOD(ofw_bus_get_node,     spi_get_node),
  596 
  597         DEVMETHOD_END
  598 };
  599 
  600 static driver_t spi_driver = {
  601         "imx_spi",
  602         spi_methods,
  603         sizeof(struct spi_softc),
  604 };
  605 
  606 DRIVER_MODULE(imx_spi, simplebus, spi_driver, 0, 0);
  607 DRIVER_MODULE(ofw_spibus, imx_spi, ofw_spibus_driver, 0, 0);
  608 MODULE_DEPEND(imx_spi, ofw_spibus, 1, 1, 1);
  609 SIMPLEBUS_PNP_INFO(compat_data);

Cache object: 875f7ad84535cd9bb3dcc26b573a7cb4


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