spibus.c revision 315329
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: stable/11/sys/dev/spibus/spibus.c 315329 2017-03-15 21:01:03Z mizhka $"); 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); 108300710Sadrian retval += printf(" mode %d", devi->mode); 109160370Simp retval += bus_print_child_footer(dev, child); 110160370Simp 111160370Simp return (retval); 112160370Simp} 113160370Simp 114160370Simpstatic void 115160370Simpspibus_probe_nomatch(device_t bus, device_t child) 116160370Simp{ 117160370Simp struct spibus_ivar *devi = SPIBUS_IVAR(child); 118160370Simp 119315329Smizhka device_printf(bus, "<unknown card> at cs %d mode %d\n", devi->cs, 120315329Smizhka devi->mode); 121160370Simp return; 122160370Simp} 123160370Simp 124160370Simpstatic int 125160370Simpspibus_child_location_str(device_t bus, device_t child, char *buf, 126160370Simp size_t buflen) 127160370Simp{ 128160370Simp struct spibus_ivar *devi = SPIBUS_IVAR(child); 129160370Simp 130160370Simp snprintf(buf, buflen, "cs=%d", devi->cs); 131160370Simp return (0); 132160370Simp} 133160370Simp 134160370Simpstatic int 135160370Simpspibus_child_pnpinfo_str(device_t bus, device_t child, char *buf, 136160370Simp size_t buflen) 137160370Simp{ 138160370Simp *buf = '\0'; 139160370Simp return (0); 140160370Simp} 141160370Simp 142160370Simpstatic int 143298651Sbrspibus_read_ivar(device_t bus, device_t child, int which, uintptr_t *result) 144160370Simp{ 145160370Simp struct spibus_ivar *devi = SPIBUS_IVAR(child); 146160370Simp 147160370Simp switch (which) { 148160370Simp default: 149160370Simp return (EINVAL); 150160370Simp case SPIBUS_IVAR_CS: 151160370Simp *(uint32_t *)result = devi->cs; 152160370Simp break; 153300710Sadrian case SPIBUS_IVAR_MODE: 154300710Sadrian *(uint32_t *)result = devi->mode; 155300710Sadrian break; 156300710Sadrian case SPIBUS_IVAR_CLOCK: 157300710Sadrian *(uint32_t *)result = devi->clock; 158300711Sadrian break; 159160370Simp } 160160370Simp return (0); 161160370Simp} 162160370Simp 163160370Simpstatic device_t 164212413Savgspibus_add_child(device_t dev, u_int order, const char *name, int unit) 165160370Simp{ 166160370Simp device_t child; 167160370Simp struct spibus_ivar *devi; 168160370Simp 169160370Simp child = device_add_child_ordered(dev, order, name, unit); 170160370Simp if (child == NULL) 171160370Simp return (child); 172160370Simp devi = malloc(sizeof(struct spibus_ivar), M_DEVBUF, M_NOWAIT | M_ZERO); 173163527Simp if (devi == NULL) { 174163527Simp device_delete_child(dev, child); 175160370Simp return (0); 176163527Simp } 177160370Simp device_set_ivars(child, devi); 178160370Simp return (child); 179160370Simp} 180160370Simp 181160370Simpstatic void 182160370Simpspibus_hinted_child(device_t bus, const char *dname, int dunit) 183160370Simp{ 184160370Simp device_t child; 185160370Simp struct spibus_ivar *devi; 186160370Simp 187160370Simp child = BUS_ADD_CHILD(bus, 0, dname, dunit); 188160370Simp devi = SPIBUS_IVAR(child); 189300710Sadrian devi->mode = SPIBUS_MODE_NONE; 190160370Simp resource_int_value(dname, dunit, "cs", &devi->cs); 191300710Sadrian resource_int_value(dname, dunit, "mode", &devi->mode); 192160370Simp} 193160370Simp 194160370Simpstatic int 195160370Simpspibus_transfer_impl(device_t dev, device_t child, struct spi_command *cmd) 196160370Simp{ 197163527Simp return (SPIBUS_TRANSFER(device_get_parent(dev), child, cmd)); 198160370Simp} 199160370Simp 200160370Simpstatic device_method_t spibus_methods[] = { 201160370Simp /* Device interface */ 202160370Simp DEVMETHOD(device_probe, spibus_probe), 203160370Simp DEVMETHOD(device_attach, spibus_attach), 204160370Simp DEVMETHOD(device_detach, spibus_detach), 205160370Simp DEVMETHOD(device_shutdown, bus_generic_shutdown), 206160370Simp DEVMETHOD(device_suspend, spibus_suspend), 207160370Simp DEVMETHOD(device_resume, spibus_resume), 208160370Simp 209160370Simp /* Bus interface */ 210160370Simp DEVMETHOD(bus_add_child, spibus_add_child), 211160370Simp DEVMETHOD(bus_print_child, spibus_print_child), 212160370Simp DEVMETHOD(bus_probe_nomatch, spibus_probe_nomatch), 213160370Simp DEVMETHOD(bus_read_ivar, spibus_read_ivar), 214160370Simp DEVMETHOD(bus_child_pnpinfo_str, spibus_child_pnpinfo_str), 215160370Simp DEVMETHOD(bus_child_location_str, spibus_child_location_str), 216160370Simp DEVMETHOD(bus_hinted_child, spibus_hinted_child), 217160370Simp 218160370Simp /* spibus interface */ 219160370Simp DEVMETHOD(spibus_transfer, spibus_transfer_impl), 220160370Simp 221227843Smarius DEVMETHOD_END 222160370Simp}; 223160370Simp 224257064Sloosdriver_t spibus_driver = { 225160370Simp "spibus", 226160370Simp spibus_methods, 227160370Simp sizeof(struct spibus_softc) 228160370Simp}; 229160370Simp 230160370Simpdevclass_t spibus_devclass; 231160370Simp 232192059SgonzoDRIVER_MODULE(spibus, spi, spibus_driver, spibus_devclass, 0, 0); 233160370SimpMODULE_VERSION(spibus, 1); 234