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-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@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 unmodified, this list of conditions, and the following
   12  *    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: stable/12/sys/mips/atheros/ar71xx_spi.c 326259 2017-11-27 15:07:26Z pfg $");
   32 
   33 #include <sys/param.h>
   34 #include <sys/systm.h>
   35 
   36 #include <sys/bus.h>
   37 #include <sys/interrupt.h>
   38 #include <sys/malloc.h>
   39 #include <sys/kernel.h>
   40 #include <sys/module.h>
   41 #include <sys/rman.h>
   42 
   43 #include <vm/vm.h>
   44 #include <vm/pmap.h>
   45 #include <vm/vm_extern.h>
   46 
   47 #include <machine/bus.h>
   48 #include <machine/cpu.h>
   49 
   50 #include <dev/spibus/spi.h>
   51 #include <dev/spibus/spibusvar.h>
   52 #include "spibus_if.h"
   53 
   54 #include <mips/atheros/ar71xxreg.h>
   55 
   56 #undef AR71XX_SPI_DEBUG
   57 #ifdef AR71XX_SPI_DEBUG
   58 #define dprintf printf
   59 #else
   60 #define dprintf(x, arg...)
   61 #endif
   62 
   63 /*
   64  * register space access macros
   65  */
   66 
   67 #define SPI_BARRIER_WRITE(sc)           bus_barrier((sc)->sc_mem_res, 0, 0,     \
   68                                             BUS_SPACE_BARRIER_WRITE)
   69 #define SPI_BARRIER_READ(sc)    bus_barrier((sc)->sc_mem_res, 0, 0,     \
   70                                             BUS_SPACE_BARRIER_READ)
   71 #define SPI_BARRIER_RW(sc)              bus_barrier((sc)->sc_mem_res, 0, 0,     \
   72                                             BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE)
   73 
   74 #define SPI_WRITE(sc, reg, val) do {                            \
   75                 bus_write_4(sc->sc_mem_res, (reg), (val));      \
   76         } while (0)
   77 
   78 #define SPI_READ(sc, reg)        bus_read_4(sc->sc_mem_res, (reg))
   79 
   80 #define SPI_SET_BITS(sc, reg, bits)     \
   81         SPI_WRITE(sc, reg, SPI_READ(sc, (reg)) | (bits))
   82 
   83 #define SPI_CLEAR_BITS(sc, reg, bits)   \
   84         SPI_WRITE(sc, reg, SPI_READ(sc, (reg)) & ~(bits))
   85 
   86 struct ar71xx_spi_softc {
   87         device_t                sc_dev;
   88         struct resource         *sc_mem_res;
   89         uint32_t                sc_reg_ctrl;
   90 };
   91 
   92 static int
   93 ar71xx_spi_probe(device_t dev)
   94 {
   95         device_set_desc(dev, "AR71XX SPI");
   96         return (BUS_PROBE_NOWILDCARD);
   97 }
   98 
   99 static int
  100 ar71xx_spi_attach(device_t dev)
  101 {
  102         struct ar71xx_spi_softc *sc = device_get_softc(dev);
  103         int rid;
  104 
  105         sc->sc_dev = dev;
  106         rid = 0;
  107         sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 
  108             RF_ACTIVE);
  109         if (!sc->sc_mem_res) {
  110                 device_printf(dev, "Could not map memory\n");
  111                 return (ENXIO);
  112         }
  113 
  114         SPI_WRITE(sc, AR71XX_SPI_FS, 1);
  115 
  116         /* Flush out read before reading the control register */
  117         SPI_BARRIER_WRITE(sc);
  118 
  119         sc->sc_reg_ctrl  = SPI_READ(sc, AR71XX_SPI_CTRL);
  120 
  121         /*
  122          * XXX TODO: document what the SPI control register does.
  123          */
  124         SPI_WRITE(sc, AR71XX_SPI_CTRL, 0x43);
  125 
  126         /*
  127          * Ensure the config register write has gone out before configuring
  128          * the chip select mask.
  129          */
  130         SPI_BARRIER_WRITE(sc);
  131         SPI_WRITE(sc, AR71XX_SPI_IO_CTRL, SPI_IO_CTRL_CSMASK);
  132 
  133         /*
  134          * .. and ensure the write has gone out before continuing.
  135          */
  136         SPI_BARRIER_WRITE(sc);
  137 
  138         device_add_child(dev, "spibus", -1);
  139         return (bus_generic_attach(dev));
  140 }
  141 
  142 static void
  143 ar71xx_spi_chip_activate(struct ar71xx_spi_softc *sc, int cs)
  144 {
  145         uint32_t ioctrl = SPI_IO_CTRL_CSMASK;
  146         /*
  147          * Put respective CSx to low
  148          */
  149         ioctrl &= ~(SPI_IO_CTRL_CS0 << cs);
  150 
  151         /*
  152          * Make sure any other writes have gone out to the
  153          * device before changing the chip select line;
  154          * then ensure that it has made it out to the device
  155          * before continuing.
  156          */
  157         SPI_BARRIER_WRITE(sc);
  158         SPI_WRITE(sc, AR71XX_SPI_IO_CTRL, ioctrl);
  159         SPI_BARRIER_WRITE(sc);
  160 }
  161 
  162 static void
  163 ar71xx_spi_chip_deactivate(struct ar71xx_spi_softc *sc, int cs)
  164 {
  165         /*
  166          * Put all CSx to high
  167          */
  168         SPI_WRITE(sc, AR71XX_SPI_IO_CTRL, SPI_IO_CTRL_CSMASK);
  169 }
  170 
  171 static uint8_t
  172 ar71xx_spi_txrx(struct ar71xx_spi_softc *sc, int cs, uint8_t data)
  173 {
  174         int bit;
  175         /* CS0 */
  176         uint32_t ioctrl = SPI_IO_CTRL_CSMASK;
  177         /*
  178          * low-level for selected CS
  179          */
  180         ioctrl &= ~(SPI_IO_CTRL_CS0 << cs);
  181 
  182         uint32_t iod, rds;
  183         for (bit = 7; bit >=0; bit--) {
  184                 if (data & (1 << bit))
  185                         iod = ioctrl | SPI_IO_CTRL_DO;
  186                 else
  187                         iod = ioctrl & ~SPI_IO_CTRL_DO;
  188                 SPI_BARRIER_WRITE(sc);
  189                 SPI_WRITE(sc, AR71XX_SPI_IO_CTRL, iod);
  190                 SPI_BARRIER_WRITE(sc);
  191                 SPI_WRITE(sc, AR71XX_SPI_IO_CTRL, iod | SPI_IO_CTRL_CLK);
  192         }
  193 
  194         /*
  195          * Provide falling edge for connected device by clear clock bit.
  196          */
  197         SPI_BARRIER_WRITE(sc);
  198         SPI_WRITE(sc, AR71XX_SPI_IO_CTRL, iod);
  199         SPI_BARRIER_WRITE(sc);
  200         rds = SPI_READ(sc, AR71XX_SPI_RDS);
  201 
  202         return (rds & 0xff);
  203 }
  204 
  205 static int
  206 ar71xx_spi_transfer(device_t dev, device_t child, struct spi_command *cmd)
  207 {
  208         struct ar71xx_spi_softc *sc;
  209         uint32_t cs;
  210         uint8_t *buf_in, *buf_out;
  211         int i;
  212 
  213         sc = device_get_softc(dev);
  214 
  215         spibus_get_cs(child, &cs);
  216 
  217         cs &= ~SPIBUS_CS_HIGH;
  218 
  219         ar71xx_spi_chip_activate(sc, cs);
  220 
  221         KASSERT(cmd->tx_cmd_sz == cmd->rx_cmd_sz, 
  222             ("TX/RX command sizes should be equal"));
  223         KASSERT(cmd->tx_data_sz == cmd->rx_data_sz, 
  224             ("TX/RX data sizes should be equal"));
  225 
  226         /*
  227          * Transfer command
  228          */
  229         buf_out = (uint8_t *)cmd->tx_cmd;
  230         buf_in = (uint8_t *)cmd->rx_cmd;
  231         for (i = 0; i < cmd->tx_cmd_sz; i++)
  232                 buf_in[i] = ar71xx_spi_txrx(sc, cs, buf_out[i]);
  233 
  234         /*
  235          * Receive/transmit data (depends on  command)
  236          */
  237         buf_out = (uint8_t *)cmd->tx_data;
  238         buf_in = (uint8_t *)cmd->rx_data;
  239         for (i = 0; i < cmd->tx_data_sz; i++)
  240                 buf_in[i] = ar71xx_spi_txrx(sc, cs, buf_out[i]);
  241 
  242         ar71xx_spi_chip_deactivate(sc, cs);
  243 
  244         return (0);
  245 }
  246 
  247 static int
  248 ar71xx_spi_detach(device_t dev)
  249 {
  250         struct ar71xx_spi_softc *sc = device_get_softc(dev);
  251 
  252         /*
  253          * Ensure any other writes to the device are finished
  254          * before we tear down the SPI device.
  255          */
  256         SPI_BARRIER_WRITE(sc);
  257 
  258         /*
  259          * Restore the control register; ensure it has hit the
  260          * hardware before continuing.
  261          */
  262         SPI_WRITE(sc, AR71XX_SPI_CTRL, sc->sc_reg_ctrl);
  263         SPI_BARRIER_WRITE(sc);
  264 
  265         /*
  266          * And now, put the flash back into mapped IO mode and
  267          * ensure _that_ has completed before we finish up.
  268          */
  269         SPI_WRITE(sc, AR71XX_SPI_FS, 0);
  270         SPI_BARRIER_WRITE(sc);
  271 
  272         if (sc->sc_mem_res)
  273                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
  274 
  275         return (0);
  276 }
  277 
  278 static device_method_t ar71xx_spi_methods[] = {
  279         /* Device interface */
  280         DEVMETHOD(device_probe,         ar71xx_spi_probe),
  281         DEVMETHOD(device_attach,        ar71xx_spi_attach),
  282         DEVMETHOD(device_detach,        ar71xx_spi_detach),
  283 
  284         DEVMETHOD(spibus_transfer,      ar71xx_spi_transfer),
  285 
  286         {0, 0}
  287 };
  288 
  289 static driver_t ar71xx_spi_driver = {
  290         "spi",
  291         ar71xx_spi_methods,
  292         sizeof(struct ar71xx_spi_softc),
  293 };
  294 
  295 static devclass_t ar71xx_spi_devclass;
  296 
  297 DRIVER_MODULE(ar71xx_spi, nexus, ar71xx_spi_driver, ar71xx_spi_devclass, 0, 0);

Cache object: 91df753e91dd9554202fa44a04d96308


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