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/mips/atheros/ar71xx_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) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice unmodified, this list of conditions, and the following
   10  *    disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 #include <sys/cdefs.h>
   29 __FBSDID("$FreeBSD: releng/11.1/sys/mips/atheros/ar71xx_spi.c 310158 2016-12-16 15:45:09Z manu $");
   30 
   31 #include <sys/param.h>
   32 #include <sys/systm.h>
   33 
   34 #include <sys/bus.h>
   35 #include <sys/interrupt.h>
   36 #include <sys/malloc.h>
   37 #include <sys/kernel.h>
   38 #include <sys/module.h>
   39 #include <sys/rman.h>
   40 
   41 #include <vm/vm.h>
   42 #include <vm/pmap.h>
   43 #include <vm/vm_extern.h>
   44 
   45 #include <machine/bus.h>
   46 #include <machine/cpu.h>
   47 
   48 #include <dev/spibus/spi.h>
   49 #include <dev/spibus/spibusvar.h>
   50 #include "spibus_if.h"
   51 
   52 #include <mips/atheros/ar71xxreg.h>
   53 
   54 #undef AR71XX_SPI_DEBUG
   55 #ifdef AR71XX_SPI_DEBUG
   56 #define dprintf printf
   57 #else
   58 #define dprintf(x, arg...)
   59 #endif
   60 
   61 /*
   62  * register space access macros
   63  */
   64 
   65 #define SPI_BARRIER_WRITE(sc)           bus_barrier((sc)->sc_mem_res, 0, 0,     \
   66                                             BUS_SPACE_BARRIER_WRITE)
   67 #define SPI_BARRIER_READ(sc)    bus_barrier((sc)->sc_mem_res, 0, 0,     \
   68                                             BUS_SPACE_BARRIER_READ)
   69 #define SPI_BARRIER_RW(sc)              bus_barrier((sc)->sc_mem_res, 0, 0,     \
   70                                             BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE)
   71 
   72 #define SPI_WRITE(sc, reg, val) do {                            \
   73                 bus_write_4(sc->sc_mem_res, (reg), (val));      \
   74         } while (0)
   75 
   76 #define SPI_READ(sc, reg)        bus_read_4(sc->sc_mem_res, (reg))
   77 
   78 #define SPI_SET_BITS(sc, reg, bits)     \
   79         SPI_WRITE(sc, reg, SPI_READ(sc, (reg)) | (bits))
   80 
   81 #define SPI_CLEAR_BITS(sc, reg, bits)   \
   82         SPI_WRITE(sc, reg, SPI_READ(sc, (reg)) & ~(bits))
   83 
   84 struct ar71xx_spi_softc {
   85         device_t                sc_dev;
   86         struct resource         *sc_mem_res;
   87         uint32_t                sc_reg_ctrl;
   88 };
   89 
   90 static int
   91 ar71xx_spi_probe(device_t dev)
   92 {
   93         device_set_desc(dev, "AR71XX SPI");
   94         return (BUS_PROBE_NOWILDCARD);
   95 }
   96 
   97 static int
   98 ar71xx_spi_attach(device_t dev)
   99 {
  100         struct ar71xx_spi_softc *sc = device_get_softc(dev);
  101         int rid;
  102 
  103         sc->sc_dev = dev;
  104         rid = 0;
  105         sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 
  106             RF_ACTIVE);
  107         if (!sc->sc_mem_res) {
  108                 device_printf(dev, "Could not map memory\n");
  109                 return (ENXIO);
  110         }
  111 
  112         SPI_WRITE(sc, AR71XX_SPI_FS, 1);
  113 
  114         /* Flush out read before reading the control register */
  115         SPI_BARRIER_WRITE(sc);
  116 
  117         sc->sc_reg_ctrl  = SPI_READ(sc, AR71XX_SPI_CTRL);
  118 
  119         /*
  120          * XXX TODO: document what the SPI control register does.
  121          */
  122         SPI_WRITE(sc, AR71XX_SPI_CTRL, 0x43);
  123 
  124         /*
  125          * Ensure the config register write has gone out before configuring
  126          * the chip select mask.
  127          */
  128         SPI_BARRIER_WRITE(sc);
  129         SPI_WRITE(sc, AR71XX_SPI_IO_CTRL, SPI_IO_CTRL_CSMASK);
  130 
  131         /*
  132          * .. and ensure the write has gone out before continuing.
  133          */
  134         SPI_BARRIER_WRITE(sc);
  135 
  136         device_add_child(dev, "spibus", -1);
  137         return (bus_generic_attach(dev));
  138 }
  139 
  140 static void
  141 ar71xx_spi_chip_activate(struct ar71xx_spi_softc *sc, int cs)
  142 {
  143         uint32_t ioctrl = SPI_IO_CTRL_CSMASK;
  144         /*
  145          * Put respective CSx to low
  146          */
  147         ioctrl &= ~(SPI_IO_CTRL_CS0 << cs);
  148 
  149         /*
  150          * Make sure any other writes have gone out to the
  151          * device before changing the chip select line;
  152          * then ensure that it has made it out to the device
  153          * before continuing.
  154          */
  155         SPI_BARRIER_WRITE(sc);
  156         SPI_WRITE(sc, AR71XX_SPI_IO_CTRL, ioctrl);
  157         SPI_BARRIER_WRITE(sc);
  158 }
  159 
  160 static void
  161 ar71xx_spi_chip_deactivate(struct ar71xx_spi_softc *sc, int cs)
  162 {
  163         /*
  164          * Put all CSx to high
  165          */
  166         SPI_WRITE(sc, AR71XX_SPI_IO_CTRL, SPI_IO_CTRL_CSMASK);
  167 }
  168 
  169 static uint8_t
  170 ar71xx_spi_txrx(struct ar71xx_spi_softc *sc, int cs, uint8_t data)
  171 {
  172         int bit;
  173         /* CS0 */
  174         uint32_t ioctrl = SPI_IO_CTRL_CSMASK;
  175         /*
  176          * low-level for selected CS
  177          */
  178         ioctrl &= ~(SPI_IO_CTRL_CS0 << cs);
  179 
  180         uint32_t iod, rds;
  181         for (bit = 7; bit >=0; bit--) {
  182                 if (data & (1 << bit))
  183                         iod = ioctrl | SPI_IO_CTRL_DO;
  184                 else
  185                         iod = ioctrl & ~SPI_IO_CTRL_DO;
  186                 SPI_BARRIER_WRITE(sc);
  187                 SPI_WRITE(sc, AR71XX_SPI_IO_CTRL, iod);
  188                 SPI_BARRIER_WRITE(sc);
  189                 SPI_WRITE(sc, AR71XX_SPI_IO_CTRL, iod | SPI_IO_CTRL_CLK);
  190         }
  191 
  192         /*
  193          * Provide falling edge for connected device by clear clock bit.
  194          */
  195         SPI_BARRIER_WRITE(sc);
  196         SPI_WRITE(sc, AR71XX_SPI_IO_CTRL, iod);
  197         SPI_BARRIER_WRITE(sc);
  198         rds = SPI_READ(sc, AR71XX_SPI_RDS);
  199 
  200         return (rds & 0xff);
  201 }
  202 
  203 static int
  204 ar71xx_spi_transfer(device_t dev, device_t child, struct spi_command *cmd)
  205 {
  206         struct ar71xx_spi_softc *sc;
  207         uint32_t cs;
  208         uint8_t *buf_in, *buf_out;
  209         int i;
  210 
  211         sc = device_get_softc(dev);
  212 
  213         spibus_get_cs(child, &cs);
  214 
  215         ar71xx_spi_chip_activate(sc, cs);
  216 
  217         KASSERT(cmd->tx_cmd_sz == cmd->rx_cmd_sz, 
  218             ("TX/RX command sizes should be equal"));
  219         KASSERT(cmd->tx_data_sz == cmd->rx_data_sz, 
  220             ("TX/RX data sizes should be equal"));
  221 
  222         /*
  223          * Transfer command
  224          */
  225         buf_out = (uint8_t *)cmd->tx_cmd;
  226         buf_in = (uint8_t *)cmd->rx_cmd;
  227         for (i = 0; i < cmd->tx_cmd_sz; i++)
  228                 buf_in[i] = ar71xx_spi_txrx(sc, cs, buf_out[i]);
  229 
  230         /*
  231          * Receive/transmit data (depends on  command)
  232          */
  233         buf_out = (uint8_t *)cmd->tx_data;
  234         buf_in = (uint8_t *)cmd->rx_data;
  235         for (i = 0; i < cmd->tx_data_sz; i++)
  236                 buf_in[i] = ar71xx_spi_txrx(sc, cs, buf_out[i]);
  237 
  238         ar71xx_spi_chip_deactivate(sc, cs);
  239 
  240         return (0);
  241 }
  242 
  243 static int
  244 ar71xx_spi_detach(device_t dev)
  245 {
  246         struct ar71xx_spi_softc *sc = device_get_softc(dev);
  247 
  248         /*
  249          * Ensure any other writes to the device are finished
  250          * before we tear down the SPI device.
  251          */
  252         SPI_BARRIER_WRITE(sc);
  253 
  254         /*
  255          * Restore the control register; ensure it has hit the
  256          * hardware before continuing.
  257          */
  258         SPI_WRITE(sc, AR71XX_SPI_CTRL, sc->sc_reg_ctrl);
  259         SPI_BARRIER_WRITE(sc);
  260 
  261         /*
  262          * And now, put the flash back into mapped IO mode and
  263          * ensure _that_ has completed before we finish up.
  264          */
  265         SPI_WRITE(sc, AR71XX_SPI_FS, 0);
  266         SPI_BARRIER_WRITE(sc);
  267 
  268         if (sc->sc_mem_res)
  269                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
  270 
  271         return (0);
  272 }
  273 
  274 static device_method_t ar71xx_spi_methods[] = {
  275         /* Device interface */
  276         DEVMETHOD(device_probe,         ar71xx_spi_probe),
  277         DEVMETHOD(device_attach,        ar71xx_spi_attach),
  278         DEVMETHOD(device_detach,        ar71xx_spi_detach),
  279 
  280         DEVMETHOD(spibus_transfer,      ar71xx_spi_transfer),
  281 
  282         {0, 0}
  283 };
  284 
  285 static driver_t ar71xx_spi_driver = {
  286         "spi",
  287         ar71xx_spi_methods,
  288         sizeof(struct ar71xx_spi_softc),
  289 };
  290 
  291 static devclass_t ar71xx_spi_devclass;
  292 
  293 DRIVER_MODULE(ar71xx_spi, nexus, ar71xx_spi_driver, ar71xx_spi_devclass, 0, 0);

Cache object: e217737b0aba17b16870c8460a358f87


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