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/10.4/sys/mips/atheros/ar71xx_spi.c 265999 2014-05-14 01:35:43Z ian $");
   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 #include <machine/pmap.h>
   48 
   49 #include <dev/spibus/spi.h>
   50 #include <dev/spibus/spibusvar.h>
   51 #include "spibus_if.h"
   52 
   53 #include <mips/atheros/ar71xxreg.h>
   54 
   55 #undef AR71XX_SPI_DEBUG
   56 #ifdef AR71XX_SPI_DEBUG
   57 #define dprintf printf
   58 #else
   59 #define dprintf(x, arg...)
   60 #endif
   61 
   62 /*
   63  * register space access macros
   64  */
   65 #define SPI_WRITE(sc, reg, val) do {    \
   66                 bus_write_4(sc->sc_mem_res, (reg), (val)); \
   67         } while (0)
   68 
   69 #define SPI_READ(sc, reg)        bus_read_4(sc->sc_mem_res, (reg))
   70 
   71 #define SPI_SET_BITS(sc, reg, bits)     \
   72         SPI_WRITE(sc, reg, SPI_READ(sc, (reg)) | (bits))
   73 
   74 #define SPI_CLEAR_BITS(sc, reg, bits)   \
   75         SPI_WRITE(sc, reg, SPI_READ(sc, (reg)) & ~(bits))
   76 
   77 struct ar71xx_spi_softc {
   78         device_t                sc_dev;
   79         struct resource         *sc_mem_res;
   80         uint32_t                sc_reg_ctrl;
   81 };
   82 
   83 static int
   84 ar71xx_spi_probe(device_t dev)
   85 {
   86         device_set_desc(dev, "AR71XX SPI");
   87         return (BUS_PROBE_NOWILDCARD);
   88 }
   89 
   90 static int
   91 ar71xx_spi_attach(device_t dev)
   92 {
   93         struct ar71xx_spi_softc *sc = device_get_softc(dev);
   94         int rid;
   95 
   96         sc->sc_dev = dev;
   97         rid = 0;
   98         sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 
   99             RF_ACTIVE);
  100         if (!sc->sc_mem_res) {
  101                 device_printf(dev, "Could not map memory\n");
  102                 return (ENXIO);
  103         }
  104 
  105 
  106         SPI_WRITE(sc, AR71XX_SPI_FS, 1);
  107         sc->sc_reg_ctrl  = SPI_READ(sc, AR71XX_SPI_CTRL);
  108         SPI_WRITE(sc, AR71XX_SPI_CTRL, 0x43);
  109         SPI_WRITE(sc, AR71XX_SPI_IO_CTRL, SPI_IO_CTRL_CSMASK);
  110 
  111         device_add_child(dev, "spibus", -1);
  112         return (bus_generic_attach(dev));
  113 }
  114 
  115 static void
  116 ar71xx_spi_chip_activate(struct ar71xx_spi_softc *sc, int cs)
  117 {
  118         uint32_t ioctrl = SPI_IO_CTRL_CSMASK;
  119         /*
  120          * Put respective CSx to low
  121          */
  122         ioctrl &= ~(SPI_IO_CTRL_CS0 << cs);
  123 
  124         SPI_WRITE(sc, AR71XX_SPI_IO_CTRL, ioctrl);
  125 }
  126 
  127 static void
  128 ar71xx_spi_chip_deactivate(struct ar71xx_spi_softc *sc, int cs)
  129 {
  130         /*
  131          * Put all CSx to high
  132          */
  133         SPI_WRITE(sc, AR71XX_SPI_IO_CTRL, SPI_IO_CTRL_CSMASK);
  134 }
  135 
  136 static uint8_t
  137 ar71xx_spi_txrx(struct ar71xx_spi_softc *sc, int cs, uint8_t data)
  138 {
  139         int bit;
  140         /* CS0 */
  141         uint32_t ioctrl = SPI_IO_CTRL_CSMASK;
  142         /*
  143          * low-level for selected CS
  144          */
  145         ioctrl &= ~(SPI_IO_CTRL_CS0 << cs);
  146 
  147         uint32_t iod, rds;
  148         for (bit = 7; bit >=0; bit--) {
  149                 if (data & (1 << bit))
  150                         iod = ioctrl | SPI_IO_CTRL_DO;
  151                 else
  152                         iod = ioctrl & ~SPI_IO_CTRL_DO;
  153                 SPI_WRITE(sc, AR71XX_SPI_IO_CTRL, iod);
  154                 SPI_WRITE(sc, AR71XX_SPI_IO_CTRL, iod | SPI_IO_CTRL_CLK);
  155         }
  156 
  157         /*
  158          * Provide falling edge for connected device by clear clock bit.
  159          */
  160         SPI_WRITE(sc, AR71XX_SPI_IO_CTRL, iod);
  161         rds = SPI_READ(sc, AR71XX_SPI_RDS);
  162 
  163         return (rds & 0xff);
  164 }
  165 
  166 static int
  167 ar71xx_spi_transfer(device_t dev, device_t child, struct spi_command *cmd)
  168 {
  169         struct ar71xx_spi_softc *sc;
  170         uint8_t *buf_in, *buf_out;
  171         struct spibus_ivar *devi = SPIBUS_IVAR(child);
  172         int i;
  173 
  174         sc = device_get_softc(dev);
  175 
  176         ar71xx_spi_chip_activate(sc, devi->cs);
  177 
  178         KASSERT(cmd->tx_cmd_sz == cmd->rx_cmd_sz, 
  179             ("TX/RX command sizes should be equal"));
  180         KASSERT(cmd->tx_data_sz == cmd->rx_data_sz, 
  181             ("TX/RX data sizes should be equal"));
  182 
  183         /*
  184          * Transfer command
  185          */
  186         buf_out = (uint8_t *)cmd->tx_cmd;
  187         buf_in = (uint8_t *)cmd->rx_cmd;
  188         for (i = 0; i < cmd->tx_cmd_sz; i++)
  189                 buf_in[i] = ar71xx_spi_txrx(sc, devi->cs, buf_out[i]);
  190 
  191         /*
  192          * Receive/transmit data (depends on  command)
  193          */
  194         buf_out = (uint8_t *)cmd->tx_data;
  195         buf_in = (uint8_t *)cmd->rx_data;
  196         for (i = 0; i < cmd->tx_data_sz; i++)
  197                 buf_in[i] = ar71xx_spi_txrx(sc, devi->cs, buf_out[i]);
  198 
  199         ar71xx_spi_chip_deactivate(sc, devi->cs);
  200 
  201         return (0);
  202 }
  203 
  204 static int
  205 ar71xx_spi_detach(device_t dev)
  206 {
  207         struct ar71xx_spi_softc *sc = device_get_softc(dev);
  208 
  209         SPI_WRITE(sc, AR71XX_SPI_CTRL, sc->sc_reg_ctrl);
  210         SPI_WRITE(sc, AR71XX_SPI_FS, 0);
  211 
  212         if (sc->sc_mem_res)
  213                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
  214 
  215         return (0);
  216 }
  217 
  218 static device_method_t ar71xx_spi_methods[] = {
  219         /* Device interface */
  220         DEVMETHOD(device_probe,         ar71xx_spi_probe),
  221         DEVMETHOD(device_attach,        ar71xx_spi_attach),
  222         DEVMETHOD(device_detach,        ar71xx_spi_detach),
  223 
  224         DEVMETHOD(spibus_transfer,      ar71xx_spi_transfer),
  225 
  226         {0, 0}
  227 };
  228 
  229 static driver_t ar71xx_spi_driver = {
  230         "spi",
  231         ar71xx_spi_methods,
  232         sizeof(struct ar71xx_spi_softc),
  233 };
  234 
  235 static devclass_t ar71xx_spi_devclass;
  236 
  237 DRIVER_MODULE(ar71xx_spi, nexus, ar71xx_spi_driver, ar71xx_spi_devclass, 0, 0);

Cache object: a3751dab96610a61afbc8067185c737d


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