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/rt305x/rt305x_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  * Copyright (c) 2011, Aleksandr Rybalko <ray@FreeBSD.org>
    4  * Copyright (c) 2013, Alexander A. Mityaev <sansan@adm.ua>
    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$");
   32 
   33 #include <sys/param.h>
   34 #include <sys/systm.h>
   35 #include <sys/bus.h>
   36 
   37 #include <sys/kernel.h>
   38 #include <sys/module.h>
   39 #include <sys/rman.h>
   40 #include <sys/lock.h>
   41 #include <sys/mutex.h>
   42 
   43 #include <machine/bus.h>
   44 #include <machine/cpu.h>
   45 //#include <machine/pmap.h>
   46 
   47 #include <dev/spibus/spi.h>
   48 #include <dev/spibus/spibusvar.h>
   49 #include "spibus_if.h"
   50 
   51 #include "opt_platform.h"
   52 
   53 #ifdef FDT
   54 #include <dev/ofw/openfirm.h>
   55 #include <dev/ofw/ofw_bus.h>
   56 #include <dev/ofw/ofw_bus_subr.h>
   57 #endif
   58 
   59 #include <mips/rt305x/rt305xreg.h>
   60 #include <dev/flash/mx25lreg.h>
   61 
   62 #undef RT305X_SPI_DEBUG
   63 #ifdef RT305X_SPI_DEBUG
   64 #define dprintf printf
   65 #else
   66 #define dprintf(x, arg...)
   67 #endif
   68 
   69 /*
   70  * register space access macros
   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 rt305x_spi_softc {
   85         device_t                sc_dev;
   86         struct resource         *sc_mem_res;
   87 };
   88 
   89 static int      rt305x_spi_probe(device_t);
   90 static int      rt305x_spi_attach(device_t);
   91 static int      rt305x_spi_detach(device_t);
   92 static int      rt305x_spi_wait(struct rt305x_spi_softc *);
   93 static void     rt305x_spi_chip_activate(struct rt305x_spi_softc *);
   94 static void     rt305x_spi_chip_deactivate(struct rt305x_spi_softc *);
   95 static uint8_t  rt305x_spi_txrx(struct rt305x_spi_softc *, uint8_t *, int);
   96 static int      rt305x_spi_transfer(device_t, device_t, struct spi_command *);
   97 #ifdef FDT
   98 static phandle_t rt305x_spi_get_node(device_t, device_t);
   99 #endif
  100 
  101 static int
  102 rt305x_spi_probe(device_t dev)
  103 {
  104 #ifdef FDT
  105         if (!ofw_bus_is_compatible(dev, "ralink,rt305x-spi"))
  106             return(ENXIO);
  107 #endif
  108         device_set_desc(dev, "RT305X SPI");
  109         return (0);
  110 }
  111 
  112 static int
  113 rt305x_spi_attach(device_t dev)
  114 {
  115         struct rt305x_spi_softc *sc = device_get_softc(dev);
  116         int rid;
  117 
  118         sc->sc_dev = dev;
  119         rid = 0;
  120         sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
  121             RF_ACTIVE);
  122         if (!sc->sc_mem_res) {
  123                 device_printf(dev, "Could not map memory\n");
  124                 return (ENXIO);
  125         }
  126 
  127         if (rt305x_spi_wait(sc)) {
  128                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
  129                 return (EBUSY);
  130         }
  131 
  132         SPI_WRITE(sc, RT305X_SPICFG, MSBFIRST | SPICLKPOL | TX_ON_CLK_FALL |
  133             SPI_CLK_DIV8); /* XXX: make it configurable */
  134             /*
  135              * W25Q64CV max 104MHz, bus 120-192 MHz, so divide by 2.
  136              * Update: divide by 4, DEV2 to fast for flash.
  137              */
  138 
  139         device_add_child(dev, "spibus", 0);
  140         return (bus_generic_attach(dev));
  141 }
  142 
  143 static int
  144 rt305x_spi_detach(device_t dev)
  145 {
  146         struct rt305x_spi_softc *sc = device_get_softc(dev);
  147 
  148         SPI_SET_BITS(sc, RT305X_SPICTL, HIZSMOSI | CS_HIGH);
  149 
  150         if (sc->sc_mem_res)
  151                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
  152 
  153         return (0);
  154 }
  155 
  156 static void
  157 rt305x_spi_chip_activate(struct rt305x_spi_softc *sc)
  158 {
  159 //        printf("%s\n", __func__);
  160         rt305x_spi_wait(sc);
  161         /*
  162          * Put all CSx to low
  163          */
  164         SPI_CLEAR_BITS(sc, RT305X_SPICTL, CS_HIGH | HIZSMOSI);
  165 }
  166 
  167 static void
  168 rt305x_spi_chip_deactivate(struct rt305x_spi_softc *sc)
  169 {
  170 //        printf("%s\n", __func__);
  171         rt305x_spi_wait(sc);
  172         /*
  173          * Put all CSx to high
  174          */
  175         SPI_SET_BITS(sc, RT305X_SPICTL, CS_HIGH | HIZSMOSI);
  176 }
  177 
  178 static int
  179 rt305x_spi_wait(struct rt305x_spi_softc *sc)
  180 {
  181         int i = 1000;
  182 
  183         while (i--) {
  184                 if (!SPI_READ(sc, RT305X_SPIBUSY))
  185                         break;
  186         }
  187         if (i == 0) {
  188                 printf("busy\n");
  189                 return (1);
  190         }
  191 
  192         return (0);
  193 }
  194 
  195 static uint8_t
  196 rt305x_spi_txrx(struct rt305x_spi_softc *sc, uint8_t *data, int write)
  197 {
  198 
  199         if (rt305x_spi_wait(sc))
  200                 return (EBUSY);
  201 
  202         if (write == RT305X_SPI_WRITE) {
  203                 SPI_WRITE(sc, RT305X_SPIDATA, *data);
  204                 SPI_SET_BITS(sc, RT305X_SPICTL, START_WRITE);
  205                 //printf("%s(W:%d)\n", __func__, *data);
  206         } else {/* RT305X_SPI_READ */
  207                 SPI_SET_BITS(sc, RT305X_SPICTL, START_READ);
  208                 if (rt305x_spi_wait(sc))
  209                         return (EBUSY);
  210 
  211                 *data = SPI_READ(sc, RT305X_SPIDATA) & 0xff;
  212                 //printf("%s(R:%d)\n", __func__, *data);
  213         }
  214         return (0);
  215 }
  216 
  217 static int
  218 rt305x_spi_transfer(device_t dev, device_t child, struct spi_command *cmd)
  219 {
  220         struct rt305x_spi_softc *sc;
  221         uint32_t cs;
  222         uint8_t *buf, byte, *tx_buf;
  223         int i, sz, error = 0, write = 0;
  224 
  225         sc = device_get_softc(dev);
  226 
  227         spibus_get_cs(child, &cs);
  228 
  229         cs &= ~SPIBUS_CS_HIGH;
  230 
  231         if (cs != 0)
  232                 /* Only 1 CS */
  233                 return (ENXIO);
  234 
  235         /* There is always a command to transfer. */
  236         tx_buf = (uint8_t *)(cmd->tx_cmd);
  237         
  238         /* Perform some fixup because RT305X dont support duplex SPI */
  239         switch(tx_buf[0]) {
  240                 case CMD_READ_IDENT:
  241                         cmd->tx_cmd_sz = 1;
  242                         cmd->rx_cmd_sz = 3;
  243                         break;
  244                 case CMD_WRITE_ENABLE:
  245                 case CMD_WRITE_DISABLE:
  246                         cmd->tx_cmd_sz = 1;
  247                         cmd->rx_cmd_sz = 0;
  248                         break;
  249                 case CMD_READ_STATUS:
  250                         cmd->tx_cmd_sz = 1;
  251                         cmd->rx_cmd_sz = 1;
  252                         break;
  253                 case CMD_READ:
  254                         cmd->tx_cmd_sz = 4;
  255                 case CMD_FAST_READ:
  256                         cmd->tx_cmd_sz = 5;
  257                         cmd->rx_cmd_sz = cmd->tx_data_sz = 0;
  258                         break;
  259                 case CMD_SECTOR_ERASE:
  260                         cmd->tx_cmd_sz = 4;
  261                         cmd->rx_cmd_sz = cmd->tx_data_sz = 0;
  262                         break;
  263                 case CMD_PAGE_PROGRAM:
  264                         cmd->tx_cmd_sz = 4;
  265                         cmd->rx_cmd_sz = cmd->rx_data_sz = 0;
  266                         break;
  267         }      
  268         
  269         rt305x_spi_chip_activate(sc);
  270 
  271         if (cmd->tx_cmd_sz + cmd->rx_cmd_sz) {
  272                 buf = (uint8_t *)(cmd->rx_cmd);
  273                 tx_buf = (uint8_t *)(cmd->tx_cmd);
  274                 sz = cmd->tx_cmd_sz + cmd->rx_cmd_sz;
  275 
  276                 for (i = 0; i < sz; i++) {
  277                         if(i < cmd->tx_cmd_sz) {
  278                                 byte = tx_buf[i];
  279                                 error = rt305x_spi_txrx(sc, &byte,
  280                                     RT305X_SPI_WRITE);
  281                                 if (error)
  282                                         goto rt305x_spi_transfer_fail;
  283                                 continue;
  284                         }
  285                         error = rt305x_spi_txrx(sc, &byte,
  286                             RT305X_SPI_READ);
  287                         if (error)
  288                                 goto rt305x_spi_transfer_fail;
  289                         buf[i] = byte;
  290                 }
  291         }
  292         
  293         /*
  294          * Transfer/Receive data
  295          */
  296         
  297         if (cmd->tx_data_sz + cmd->rx_data_sz) {
  298                 write = (cmd->tx_data_sz > 0)?1:0;
  299                 buf = (uint8_t *)(write ? cmd->tx_data : cmd->rx_data);
  300                 sz = write ? cmd->tx_data_sz : cmd->rx_data_sz;
  301 
  302                 for (i = 0; i < sz; i++) {
  303                         byte = buf[i];
  304                         error = rt305x_spi_txrx(sc, &byte,
  305                             write?RT305X_SPI_WRITE:RT305X_SPI_READ);
  306                         if (error)
  307                                 goto rt305x_spi_transfer_fail;
  308                         buf[i] = byte;
  309                 }
  310         }
  311 rt305x_spi_transfer_fail:
  312         rt305x_spi_chip_deactivate(sc);
  313 
  314         return (error);
  315 }
  316 
  317 #ifdef FDT
  318 static phandle_t
  319 rt305x_spi_get_node(device_t bus, device_t dev)
  320 {
  321 
  322         /* We only have one child, the SPI bus, which needs our own node. */
  323         return (ofw_bus_get_node(bus));
  324 }
  325 #endif
  326 
  327 static device_method_t rt305x_spi_methods[] = {
  328         /* Device interface */
  329         DEVMETHOD(device_probe,         rt305x_spi_probe),
  330         DEVMETHOD(device_attach,        rt305x_spi_attach),
  331         DEVMETHOD(device_detach,        rt305x_spi_detach),
  332 
  333         DEVMETHOD(spibus_transfer,      rt305x_spi_transfer),
  334 
  335 #ifdef FDT
  336         /* ofw_bus interface */
  337         DEVMETHOD(ofw_bus_get_node,     rt305x_spi_get_node),
  338 #endif
  339 
  340         DEVMETHOD_END
  341 };
  342 
  343 static driver_t rt305x_spi_driver = {
  344         .name = "spi",
  345         .methods = rt305x_spi_methods,
  346         .size = sizeof(struct rt305x_spi_softc),
  347 };
  348 
  349 static devclass_t rt305x_spi_devclass;
  350 
  351 DRIVER_MODULE(rt305x_spi, obio, rt305x_spi_driver, rt305x_spi_devclass, 0, 0);
  352 #ifdef FDT
  353 DRIVER_MODULE(rt305x_spi, simplebus, rt305x_spi_driver, rt305x_spi_devclass, 0, 0);
  354 #endif

Cache object: 7d44937d5fd18a2d3d27f51ef5d28819


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