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.0/sys/mips/atheros/ar71xx_spi.c 295880 2016-02-22 09:02:20Z skra $");
   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         uint8_t *buf_in, *buf_out;
  208         struct spibus_ivar *devi = SPIBUS_IVAR(child);
  209         int i;
  210 
  211         sc = device_get_softc(dev);
  212 
  213         ar71xx_spi_chip_activate(sc, devi->cs);
  214 
  215         KASSERT(cmd->tx_cmd_sz == cmd->rx_cmd_sz, 
  216             ("TX/RX command sizes should be equal"));
  217         KASSERT(cmd->tx_data_sz == cmd->rx_data_sz, 
  218             ("TX/RX data sizes should be equal"));
  219 
  220         /*
  221          * Transfer command
  222          */
  223         buf_out = (uint8_t *)cmd->tx_cmd;
  224         buf_in = (uint8_t *)cmd->rx_cmd;
  225         for (i = 0; i < cmd->tx_cmd_sz; i++)
  226                 buf_in[i] = ar71xx_spi_txrx(sc, devi->cs, buf_out[i]);
  227 
  228         /*
  229          * Receive/transmit data (depends on  command)
  230          */
  231         buf_out = (uint8_t *)cmd->tx_data;
  232         buf_in = (uint8_t *)cmd->rx_data;
  233         for (i = 0; i < cmd->tx_data_sz; i++)
  234                 buf_in[i] = ar71xx_spi_txrx(sc, devi->cs, buf_out[i]);
  235 
  236         ar71xx_spi_chip_deactivate(sc, devi->cs);
  237 
  238         return (0);
  239 }
  240 
  241 static int
  242 ar71xx_spi_detach(device_t dev)
  243 {
  244         struct ar71xx_spi_softc *sc = device_get_softc(dev);
  245 
  246         /*
  247          * Ensure any other writes to the device are finished
  248          * before we tear down the SPI device.
  249          */
  250         SPI_BARRIER_WRITE(sc);
  251 
  252         /*
  253          * Restore the control register; ensure it has hit the
  254          * hardware before continuing.
  255          */
  256         SPI_WRITE(sc, AR71XX_SPI_CTRL, sc->sc_reg_ctrl);
  257         SPI_BARRIER_WRITE(sc);
  258 
  259         /*
  260          * And now, put the flash back into mapped IO mode and
  261          * ensure _that_ has completed before we finish up.
  262          */
  263         SPI_WRITE(sc, AR71XX_SPI_FS, 0);
  264         SPI_BARRIER_WRITE(sc);
  265 
  266         if (sc->sc_mem_res)
  267                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
  268 
  269         return (0);
  270 }
  271 
  272 static device_method_t ar71xx_spi_methods[] = {
  273         /* Device interface */
  274         DEVMETHOD(device_probe,         ar71xx_spi_probe),
  275         DEVMETHOD(device_attach,        ar71xx_spi_attach),
  276         DEVMETHOD(device_detach,        ar71xx_spi_detach),
  277 
  278         DEVMETHOD(spibus_transfer,      ar71xx_spi_transfer),
  279 
  280         {0, 0}
  281 };
  282 
  283 static driver_t ar71xx_spi_driver = {
  284         "spi",
  285         ar71xx_spi_methods,
  286         sizeof(struct ar71xx_spi_softc),
  287 };
  288 
  289 static devclass_t ar71xx_spi_devclass;
  290 
  291 DRIVER_MODULE(ar71xx_spi, nexus, ar71xx_spi_driver, ar71xx_spi_devclass, 0, 0);

Cache object: b4679e5862fe2f4de5cc7954af4aeffc


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