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$");
   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         int cs;
  126 
  127         cs = devi->cs & ~SPIBUS_CS_HIGH; /* trim 'cs high' bit */
  128         snprintf(buf, buflen, "bus=%d cs=%d", device_get_unit(bus), cs);
  129         return (0);
  130 }
  131 
  132 static int
  133 spibus_child_pnpinfo_str(device_t bus, device_t child, char *buf,
  134     size_t buflen)
  135 {
  136         *buf = '\0';
  137         return (0);
  138 }
  139 
  140 static int
  141 spibus_read_ivar(device_t bus, device_t child, int which, uintptr_t *result)
  142 {
  143         struct spibus_ivar *devi = SPIBUS_IVAR(child);
  144 
  145         switch (which) {
  146         default:
  147                 return (EINVAL);
  148         case SPIBUS_IVAR_CS:
  149                 *(uint32_t *)result = devi->cs;
  150                 break;
  151         case SPIBUS_IVAR_MODE:
  152                 *(uint32_t *)result = devi->mode;
  153                 break;
  154         case SPIBUS_IVAR_CLOCK:
  155                 *(uint32_t *)result = devi->clock;
  156                 break;
  157         }
  158         return (0);
  159 }
  160 
  161 static int
  162 spibus_write_ivar(device_t bus, device_t child, int which, uintptr_t value)
  163 {
  164         struct spibus_ivar *devi = SPIBUS_IVAR(child);
  165 
  166         if (devi == NULL || device_get_parent(child) != bus)
  167                 return (EDOOFUS);
  168 
  169         switch (which) {
  170         case SPIBUS_IVAR_CLOCK:
  171                 /* Any non-zero value is allowed for max clock frequency. */
  172                 if (value == 0)
  173                         return (EINVAL);
  174                 devi->clock = (uint32_t)value;
  175                 break;
  176         case SPIBUS_IVAR_CS:
  177                  /* Chip select cannot be changed. */
  178                 return (EINVAL);
  179         case SPIBUS_IVAR_MODE:
  180                 /* Valid SPI modes are 0-3. */
  181                 if (value > 3)
  182                         return (EINVAL);
  183                 devi->mode = (uint32_t)value;
  184                 break;
  185         default:
  186                 return (EINVAL);
  187         }
  188 
  189         return (0);
  190 }
  191 
  192 static device_t
  193 spibus_add_child(device_t dev, u_int order, const char *name, int unit)
  194 {
  195         device_t child;
  196         struct spibus_ivar *devi;
  197 
  198         child = device_add_child_ordered(dev, order, name, unit);
  199         if (child == NULL) 
  200                 return (child);
  201         devi = malloc(sizeof(struct spibus_ivar), M_DEVBUF, M_NOWAIT | M_ZERO);
  202         if (devi == NULL) {
  203                 device_delete_child(dev, child);
  204                 return (0);
  205         }
  206         device_set_ivars(child, devi);
  207         return (child);
  208 }
  209 
  210 static void
  211 spibus_hinted_child(device_t bus, const char *dname, int dunit)
  212 {
  213         device_t child;
  214         struct spibus_ivar *devi;
  215 
  216         child = BUS_ADD_CHILD(bus, 0, dname, dunit);
  217         devi = SPIBUS_IVAR(child);
  218         devi->mode = SPIBUS_MODE_NONE;
  219         resource_int_value(dname, dunit, "clock", &devi->clock);
  220         resource_int_value(dname, dunit, "cs", &devi->cs);
  221         resource_int_value(dname, dunit, "mode", &devi->mode);
  222 }
  223 
  224 static int
  225 spibus_transfer_impl(device_t dev, device_t child, struct spi_command *cmd)
  226 {
  227         return (SPIBUS_TRANSFER(device_get_parent(dev), child, cmd));
  228 }
  229 
  230 static device_method_t spibus_methods[] = {
  231         /* Device interface */
  232         DEVMETHOD(device_probe,         spibus_probe),
  233         DEVMETHOD(device_attach,        spibus_attach),
  234         DEVMETHOD(device_detach,        spibus_detach),
  235         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
  236         DEVMETHOD(device_suspend,       spibus_suspend),
  237         DEVMETHOD(device_resume,        spibus_resume),
  238 
  239         /* Bus interface */
  240         DEVMETHOD(bus_add_child,        spibus_add_child),
  241         DEVMETHOD(bus_print_child,      spibus_print_child),
  242         DEVMETHOD(bus_probe_nomatch,    spibus_probe_nomatch),
  243         DEVMETHOD(bus_read_ivar,        spibus_read_ivar),
  244         DEVMETHOD(bus_write_ivar,       spibus_write_ivar),
  245         DEVMETHOD(bus_child_pnpinfo_str, spibus_child_pnpinfo_str),
  246         DEVMETHOD(bus_child_location_str, spibus_child_location_str),
  247         DEVMETHOD(bus_hinted_child,     spibus_hinted_child),
  248 
  249         /* spibus interface */
  250         DEVMETHOD(spibus_transfer,      spibus_transfer_impl),
  251 
  252         DEVMETHOD_END
  253 };
  254 
  255 driver_t spibus_driver = {
  256         "spibus",
  257         spibus_methods,
  258         sizeof(struct spibus_softc)
  259 };
  260 
  261 devclass_t      spibus_devclass;
  262 
  263 DRIVER_MODULE(spibus, spi, spibus_driver, spibus_devclass, 0, 0);
  264 MODULE_VERSION(spibus, 1);

Cache object: 3ce250bf22b5e48750173c7a0ca91b8c


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