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/dev/spibus/spibus.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) 2006 M. Warner Losh
    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, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  *
   26  */
   27 
   28 #include <sys/cdefs.h>
   29 __FBSDID("$FreeBSD: releng/11.2/sys/dev/spibus/spibus.c 332942 2018-04-24 17:00:08Z ian $");
   30 
   31 #include <sys/param.h>
   32 #include <sys/systm.h>
   33 #include <sys/malloc.h>
   34 #include <sys/module.h>
   35 #include <sys/kernel.h>
   36 #include <sys/queue.h>
   37 #include <sys/sysctl.h>
   38 #include <sys/types.h>
   39 
   40 #include <sys/bus.h>
   41 #include <machine/bus.h>
   42 #include <sys/rman.h>
   43 #include <machine/resource.h>
   44 
   45 #include <dev/spibus/spibusvar.h>
   46 #include <dev/spibus/spi.h>
   47 #include "spibus_if.h"
   48 
   49 static int
   50 spibus_probe(device_t dev)
   51 {
   52 
   53         device_set_desc(dev, "SPI bus");
   54         return (BUS_PROBE_DEFAULT);
   55 }
   56 
   57 static int
   58 spibus_attach(device_t dev)
   59 {
   60         struct spibus_softc *sc = SPIBUS_SOFTC(dev);
   61 
   62         sc->dev = dev;
   63         bus_enumerate_hinted_children(dev);
   64         return (bus_generic_attach(dev));
   65 }
   66 
   67 /*
   68  * Since this is not a self-enumerating bus, and since we always add
   69  * children in attach, we have to always delete children here.
   70  */
   71 static int
   72 spibus_detach(device_t dev)
   73 {
   74         int err;
   75 
   76         if ((err = bus_generic_detach(dev)) != 0)
   77                 return (err);
   78         device_delete_children(dev);
   79 
   80         return (0);
   81 }
   82 
   83 static int
   84 spibus_suspend(device_t dev)
   85 {
   86         return (bus_generic_suspend(dev));
   87 }
   88 
   89 static
   90 int
   91 spibus_resume(device_t dev)
   92 {
   93         return (bus_generic_resume(dev));
   94 }
   95 
   96 static int
   97 spibus_print_child(device_t dev, device_t child)
   98 {
   99         struct spibus_ivar *devi = SPIBUS_IVAR(child);
  100         int retval = 0;
  101 
  102         retval += bus_print_child_header(dev, child);
  103         retval += printf(" at cs %d", devi->cs);
  104         retval += printf(" mode %d", devi->mode);
  105         retval += bus_print_child_footer(dev, child);
  106 
  107         return (retval);
  108 }
  109 
  110 static void
  111 spibus_probe_nomatch(device_t bus, device_t child)
  112 {
  113         struct spibus_ivar *devi = SPIBUS_IVAR(child);
  114 
  115         device_printf(bus, "<unknown card> at cs %d mode %d\n", devi->cs,
  116             devi->mode);
  117         return;
  118 }
  119 
  120 static int
  121 spibus_child_location_str(device_t bus, device_t child, char *buf,
  122     size_t buflen)
  123 {
  124         struct spibus_ivar *devi = SPIBUS_IVAR(child);
  125 
  126         snprintf(buf, buflen, "cs=%d", devi->cs);
  127         return (0);
  128 }
  129 
  130 static int
  131 spibus_child_pnpinfo_str(device_t bus, device_t child, char *buf,
  132     size_t buflen)
  133 {
  134         *buf = '\0';
  135         return (0);
  136 }
  137 
  138 static int
  139 spibus_read_ivar(device_t bus, device_t child, int which, uintptr_t *result)
  140 {
  141         struct spibus_ivar *devi = SPIBUS_IVAR(child);
  142 
  143         switch (which) {
  144         default:
  145                 return (EINVAL);
  146         case SPIBUS_IVAR_CS:
  147                 *(uint32_t *)result = devi->cs;
  148                 break;
  149         case SPIBUS_IVAR_MODE:
  150                 *(uint32_t *)result = devi->mode;
  151                 break;
  152         case SPIBUS_IVAR_CLOCK:
  153                 *(uint32_t *)result = devi->clock;
  154                 break;
  155         }
  156         return (0);
  157 }
  158 
  159 static int
  160 spibus_write_ivar(device_t bus, device_t child, int which, uintptr_t value)
  161 {
  162         struct spibus_ivar *devi = SPIBUS_IVAR(child);
  163 
  164         if (devi == NULL || device_get_parent(child) != bus)
  165                 return (EDOOFUS);
  166 
  167         switch (which) {
  168         case SPIBUS_IVAR_CLOCK:
  169                 /* Any non-zero value is allowed for max clock frequency. */
  170                 if (value == 0)
  171                         return (EINVAL);
  172                 devi->clock = (uint32_t)value;
  173                 break;
  174         case SPIBUS_IVAR_CS:
  175                  /* Chip select cannot be changed. */
  176                 return (EINVAL);
  177         case SPIBUS_IVAR_MODE:
  178                 /* Valid SPI modes are 0-3. */
  179                 if (value > 3)
  180                         return (EINVAL);
  181                 devi->mode = (uint32_t)value;
  182                 break;
  183         default:
  184                 return (EINVAL);
  185         }
  186 
  187         return (0);
  188 }
  189 
  190 static device_t
  191 spibus_add_child(device_t dev, u_int order, const char *name, int unit)
  192 {
  193         device_t child;
  194         struct spibus_ivar *devi;
  195 
  196         child = device_add_child_ordered(dev, order, name, unit);
  197         if (child == NULL) 
  198                 return (child);
  199         devi = malloc(sizeof(struct spibus_ivar), M_DEVBUF, M_NOWAIT | M_ZERO);
  200         if (devi == NULL) {
  201                 device_delete_child(dev, child);
  202                 return (0);
  203         }
  204         device_set_ivars(child, devi);
  205         return (child);
  206 }
  207 
  208 static void
  209 spibus_hinted_child(device_t bus, const char *dname, int dunit)
  210 {
  211         device_t child;
  212         struct spibus_ivar *devi;
  213 
  214         child = BUS_ADD_CHILD(bus, 0, dname, dunit);
  215         devi = SPIBUS_IVAR(child);
  216         devi->mode = SPIBUS_MODE_NONE;
  217         resource_int_value(dname, dunit, "cs", &devi->cs);
  218         resource_int_value(dname, dunit, "mode", &devi->mode);
  219 }
  220 
  221 static int
  222 spibus_transfer_impl(device_t dev, device_t child, struct spi_command *cmd)
  223 {
  224         return (SPIBUS_TRANSFER(device_get_parent(dev), child, cmd));
  225 }
  226 
  227 static device_method_t spibus_methods[] = {
  228         /* Device interface */
  229         DEVMETHOD(device_probe,         spibus_probe),
  230         DEVMETHOD(device_attach,        spibus_attach),
  231         DEVMETHOD(device_detach,        spibus_detach),
  232         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
  233         DEVMETHOD(device_suspend,       spibus_suspend),
  234         DEVMETHOD(device_resume,        spibus_resume),
  235 
  236         /* Bus interface */
  237         DEVMETHOD(bus_add_child,        spibus_add_child),
  238         DEVMETHOD(bus_print_child,      spibus_print_child),
  239         DEVMETHOD(bus_probe_nomatch,    spibus_probe_nomatch),
  240         DEVMETHOD(bus_read_ivar,        spibus_read_ivar),
  241         DEVMETHOD(bus_write_ivar,       spibus_write_ivar),
  242         DEVMETHOD(bus_child_pnpinfo_str, spibus_child_pnpinfo_str),
  243         DEVMETHOD(bus_child_location_str, spibus_child_location_str),
  244         DEVMETHOD(bus_hinted_child,     spibus_hinted_child),
  245 
  246         /* spibus interface */
  247         DEVMETHOD(spibus_transfer,      spibus_transfer_impl),
  248 
  249         DEVMETHOD_END
  250 };
  251 
  252 driver_t spibus_driver = {
  253         "spibus",
  254         spibus_methods,
  255         sizeof(struct spibus_softc)
  256 };
  257 
  258 devclass_t      spibus_devclass;
  259 
  260 DRIVER_MODULE(spibus, spi, spibus_driver, spibus_devclass, 0, 0);
  261 MODULE_VERSION(spibus, 1);

Cache object: 39020caa75318943b0e18e13dd54a70f


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