spibus.c revision 278957
1278957Simp/*- 2278957Simp * Copyright (c) 2006 M. Warner Losh 3278957Simp * All rights reserved. 4278957Simp * 5278957Simp * Redistribution and use in source and binary forms, with or without 6278957Simp * modification, are permitted provided that the following conditions 7278957Simp * are met: 8278957Simp * 1. Redistributions of source code must retain the above copyright 9278957Simp * notice, this list of conditions and the following disclaimer. 10278957Simp * 2. Redistributions in binary form must reproduce the above copyright 11278957Simp * notice, this list of conditions and the following disclaimer in the 12278957Simp * documentation and/or other materials provided with the distribution. 13278957Simp * 14278957Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15278957Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16278957Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17278957Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18278957Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19278957Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20278957Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21278957Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22278957Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23278957Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24278957Simp * SUCH DAMAGE. 25278957Simp * 26278957Simp */ 27278957Simp 28160370Simp#include <sys/cdefs.h> 29160370Simp__FBSDID("$FreeBSD: head/sys/dev/spibus/spibus.c 278957 2015-02-18 14:33:33Z imp $"); 30160370Simp 31160370Simp#include <sys/param.h> 32160370Simp#include <sys/systm.h> 33160370Simp#include <sys/malloc.h> 34160370Simp#include <sys/module.h> 35160370Simp#include <sys/kernel.h> 36160370Simp#include <sys/queue.h> 37160370Simp#include <sys/sysctl.h> 38160370Simp#include <sys/types.h> 39160370Simp 40160370Simp#include <sys/bus.h> 41160370Simp#include <machine/bus.h> 42160370Simp#include <sys/rman.h> 43160370Simp#include <machine/resource.h> 44160370Simp 45160370Simp#include <dev/spibus/spibusvar.h> 46160370Simp#include <dev/spibus/spi.h> 47160370Simp#include "spibus_if.h" 48160370Simp 49160370Simpstatic int 50160370Simpspibus_probe(device_t dev) 51160370Simp{ 52160370Simp device_set_desc(dev, "spibus bus"); 53257064Sloos return (BUS_PROBE_GENERIC); 54160370Simp} 55160370Simp 56160370Simpstatic int 57160370Simpspibus_attach(device_t dev) 58160370Simp{ 59160370Simp struct spibus_softc *sc = SPIBUS_SOFTC(dev); 60160370Simp 61160370Simp sc->dev = dev; 62160370Simp bus_enumerate_hinted_children(dev); 63160370Simp return (bus_generic_attach(dev)); 64160370Simp} 65160370Simp 66160370Simp/* 67160370Simp * Since this is not a self-enumerating bus, and since we always add 68160370Simp * children in attach, we have to always delete children here. 69160370Simp */ 70160370Simpstatic int 71160370Simpspibus_detach(device_t dev) 72160370Simp{ 73160370Simp int err, ndevs, i; 74160370Simp device_t *devlist; 75160370Simp 76160370Simp if ((err = bus_generic_detach(dev)) != 0) 77160370Simp return (err); 78160370Simp if ((err = device_get_children(dev, &devlist, &ndevs)) != 0) 79160370Simp return (err); 80160370Simp for (i = 0; i < ndevs; i++) 81160370Simp device_delete_child(dev, devlist[i]); 82160370Simp free(devlist, M_TEMP); 83160370Simp 84160370Simp return (0); 85160370Simp} 86160370Simp 87160370Simpstatic int 88160370Simpspibus_suspend(device_t dev) 89160370Simp{ 90160370Simp return (bus_generic_suspend(dev)); 91160370Simp} 92160370Simp 93160370Simpstatic 94160370Simpint 95160370Simpspibus_resume(device_t dev) 96160370Simp{ 97160370Simp return (bus_generic_resume(dev)); 98160370Simp} 99160370Simp 100160370Simpstatic int 101160370Simpspibus_print_child(device_t dev, device_t child) 102160370Simp{ 103160370Simp struct spibus_ivar *devi = SPIBUS_IVAR(child); 104160370Simp int retval = 0; 105160370Simp 106160370Simp retval += bus_print_child_header(dev, child); 107160370Simp retval += printf(" at cs %d", devi->cs); 108160370Simp retval += bus_print_child_footer(dev, child); 109160370Simp 110160370Simp return (retval); 111160370Simp} 112160370Simp 113160370Simpstatic void 114160370Simpspibus_probe_nomatch(device_t bus, device_t child) 115160370Simp{ 116160370Simp struct spibus_ivar *devi = SPIBUS_IVAR(child); 117160370Simp 118160370Simp device_printf(bus, "<unknown card>"); 119160370Simp printf(" at cs %d\n", devi->cs); 120160370Simp return; 121160370Simp} 122160370Simp 123160370Simpstatic int 124160370Simpspibus_child_location_str(device_t bus, device_t child, char *buf, 125160370Simp size_t buflen) 126160370Simp{ 127160370Simp struct spibus_ivar *devi = SPIBUS_IVAR(child); 128160370Simp 129160370Simp snprintf(buf, buflen, "cs=%d", devi->cs); 130160370Simp return (0); 131160370Simp} 132160370Simp 133160370Simpstatic int 134160370Simpspibus_child_pnpinfo_str(device_t bus, device_t child, char *buf, 135160370Simp size_t buflen) 136160370Simp{ 137160370Simp *buf = '\0'; 138160370Simp return (0); 139160370Simp} 140160370Simp 141160370Simpstatic int 142194020Savgspibus_read_ivar(device_t bus, device_t child, int which, u_int *result) 143160370Simp{ 144160370Simp struct spibus_ivar *devi = SPIBUS_IVAR(child); 145160370Simp 146160370Simp switch (which) { 147160370Simp default: 148160370Simp return (EINVAL); 149160370Simp case SPIBUS_IVAR_CS: 150160370Simp *(uint32_t *)result = devi->cs; 151160370Simp break; 152160370Simp } 153160370Simp return (0); 154160370Simp} 155160370Simp 156160370Simpstatic device_t 157212413Savgspibus_add_child(device_t dev, u_int order, const char *name, int unit) 158160370Simp{ 159160370Simp device_t child; 160160370Simp struct spibus_ivar *devi; 161160370Simp 162160370Simp child = device_add_child_ordered(dev, order, name, unit); 163160370Simp if (child == NULL) 164160370Simp return (child); 165160370Simp devi = malloc(sizeof(struct spibus_ivar), M_DEVBUF, M_NOWAIT | M_ZERO); 166163527Simp if (devi == NULL) { 167163527Simp device_delete_child(dev, child); 168160370Simp return (0); 169163527Simp } 170160370Simp device_set_ivars(child, devi); 171160370Simp return (child); 172160370Simp} 173160370Simp 174160370Simpstatic void 175160370Simpspibus_hinted_child(device_t bus, const char *dname, int dunit) 176160370Simp{ 177160370Simp device_t child; 178160370Simp struct spibus_ivar *devi; 179160370Simp 180160370Simp child = BUS_ADD_CHILD(bus, 0, dname, dunit); 181160370Simp devi = SPIBUS_IVAR(child); 182160370Simp resource_int_value(dname, dunit, "cs", &devi->cs); 183160370Simp} 184160370Simp 185160370Simpstatic int 186160370Simpspibus_transfer_impl(device_t dev, device_t child, struct spi_command *cmd) 187160370Simp{ 188163527Simp return (SPIBUS_TRANSFER(device_get_parent(dev), child, cmd)); 189160370Simp} 190160370Simp 191160370Simpstatic device_method_t spibus_methods[] = { 192160370Simp /* Device interface */ 193160370Simp DEVMETHOD(device_probe, spibus_probe), 194160370Simp DEVMETHOD(device_attach, spibus_attach), 195160370Simp DEVMETHOD(device_detach, spibus_detach), 196160370Simp DEVMETHOD(device_shutdown, bus_generic_shutdown), 197160370Simp DEVMETHOD(device_suspend, spibus_suspend), 198160370Simp DEVMETHOD(device_resume, spibus_resume), 199160370Simp 200160370Simp /* Bus interface */ 201160370Simp DEVMETHOD(bus_add_child, spibus_add_child), 202160370Simp DEVMETHOD(bus_print_child, spibus_print_child), 203160370Simp DEVMETHOD(bus_probe_nomatch, spibus_probe_nomatch), 204160370Simp DEVMETHOD(bus_read_ivar, spibus_read_ivar), 205160370Simp DEVMETHOD(bus_child_pnpinfo_str, spibus_child_pnpinfo_str), 206160370Simp DEVMETHOD(bus_child_location_str, spibus_child_location_str), 207160370Simp DEVMETHOD(bus_hinted_child, spibus_hinted_child), 208160370Simp 209160370Simp /* spibus interface */ 210160370Simp DEVMETHOD(spibus_transfer, spibus_transfer_impl), 211160370Simp 212227843Smarius DEVMETHOD_END 213160370Simp}; 214160370Simp 215257064Sloosdriver_t spibus_driver = { 216160370Simp "spibus", 217160370Simp spibus_methods, 218160370Simp sizeof(struct spibus_softc) 219160370Simp}; 220160370Simp 221160370Simpdevclass_t spibus_devclass; 222160370Simp 223192059SgonzoDRIVER_MODULE(spibus, spi, spibus_driver, spibus_devclass, 0, 0); 224160370SimpMODULE_VERSION(spibus, 1); 225