1230424Shselasky/*- 2230424Shselasky * Copyright (c) 2012 Hans Petter Selasky. All rights reserved. 3230424Shselasky * 4230424Shselasky * Redistribution and use in source and binary forms, with or without 5230424Shselasky * modification, are permitted provided that the following conditions 6230424Shselasky * are met: 7230424Shselasky * 1. Redistributions of source code must retain the above copyright 8230424Shselasky * notice, this list of conditions and the following disclaimer. 9230424Shselasky * 2. Redistributions in binary form must reproduce the above copyright 10230424Shselasky * notice, this list of conditions and the following disclaimer in the 11230424Shselasky * documentation and/or other materials provided with the distribution. 12230424Shselasky * 13230424Shselasky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14230424Shselasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15230424Shselasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16230424Shselasky * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17230424Shselasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18230424Shselasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19230424Shselasky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20230424Shselasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21230424Shselasky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22230424Shselasky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23230424Shselasky * SUCH DAMAGE. 24230424Shselasky */ 25230424Shselasky 26230424Shselasky#include <sys/cdefs.h> 27230424Shselasky__FBSDID("$FreeBSD: releng/10.3/sys/dev/usb/controller/dwc_otg_atmelarm.c 278278 2015-02-05 20:03:02Z hselasky $"); 28230424Shselasky 29230424Shselasky#include <sys/stdint.h> 30230424Shselasky#include <sys/stddef.h> 31230424Shselasky#include <sys/param.h> 32230424Shselasky#include <sys/queue.h> 33230424Shselasky#include <sys/types.h> 34230424Shselasky#include <sys/systm.h> 35230424Shselasky#include <sys/kernel.h> 36230424Shselasky#include <sys/bus.h> 37230424Shselasky#include <sys/module.h> 38230424Shselasky#include <sys/lock.h> 39230424Shselasky#include <sys/mutex.h> 40230424Shselasky#include <sys/condvar.h> 41230424Shselasky#include <sys/sysctl.h> 42230424Shselasky#include <sys/sx.h> 43230424Shselasky#include <sys/unistd.h> 44230424Shselasky#include <sys/callout.h> 45230424Shselasky#include <sys/malloc.h> 46230424Shselasky#include <sys/priv.h> 47232539Shselasky#include <sys/rman.h> 48230424Shselasky 49230424Shselasky#include <dev/usb/usb.h> 50230424Shselasky#include <dev/usb/usbdi.h> 51230424Shselasky 52230424Shselasky#include <dev/usb/usb_core.h> 53230424Shselasky#include <dev/usb/usb_busdma.h> 54230424Shselasky#include <dev/usb/usb_process.h> 55230424Shselasky#include <dev/usb/usb_util.h> 56230424Shselasky 57230424Shselasky#include <dev/usb/usb_controller.h> 58230424Shselasky#include <dev/usb/usb_bus.h> 59230424Shselasky 60230424Shselasky#include <dev/usb/controller/dwc_otg.h> 61230424Shselasky 62230424Shselaskystatic device_probe_t dwc_otg_probe; 63230424Shselaskystatic device_attach_t dwc_otg_attach; 64230424Shselaskystatic device_detach_t dwc_otg_detach; 65230424Shselasky 66230424Shselaskystruct dwc_otg_super_softc { 67230424Shselasky struct dwc_otg_softc sc_otg; /* must be first */ 68230424Shselasky}; 69230424Shselasky 70230424Shselaskystatic int 71230424Shselaskydwc_otg_probe(device_t dev) 72230424Shselasky{ 73230424Shselasky device_set_desc(dev, "DWC OTG 2.0 integrated USB controller"); 74230424Shselasky return (0); 75230424Shselasky} 76230424Shselasky 77230424Shselaskystatic int 78230424Shselaskydwc_otg_attach(device_t dev) 79230424Shselasky{ 80230424Shselasky struct dwc_otg_super_softc *sc = device_get_softc(dev); 81230424Shselasky int err; 82230424Shselasky int rid; 83230424Shselasky 84230424Shselasky /* initialise some bus fields */ 85230424Shselasky sc->sc_otg.sc_bus.parent = dev; 86230424Shselasky sc->sc_otg.sc_bus.devices = sc->sc_otg.sc_devices; 87230424Shselasky sc->sc_otg.sc_bus.devices_max = DWC_OTG_MAX_DEVICES; 88278278Shselasky sc->sc_otg.sc_bus.dma_bits = 32; 89230424Shselasky 90230424Shselasky /* get all DMA memory */ 91230424Shselasky if (usb_bus_mem_alloc_all(&sc->sc_otg.sc_bus, 92230424Shselasky USB_GET_DMA_TAG(dev), NULL)) { 93230424Shselasky return (ENOMEM); 94230424Shselasky } 95230424Shselasky rid = 0; 96230424Shselasky sc->sc_otg.sc_io_res = 97230424Shselasky bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 98230424Shselasky 99230424Shselasky if (!(sc->sc_otg.sc_io_res)) { 100230424Shselasky err = ENOMEM; 101230424Shselasky goto error; 102230424Shselasky } 103230424Shselasky sc->sc_otg.sc_io_tag = rman_get_bustag(sc->sc_otg.sc_io_res); 104230424Shselasky sc->sc_otg.sc_io_hdl = rman_get_bushandle(sc->sc_otg.sc_io_res); 105230424Shselasky sc->sc_otg.sc_io_size = rman_get_size(sc->sc_otg.sc_io_res); 106230424Shselasky 107230424Shselasky rid = 0; 108230424Shselasky sc->sc_otg.sc_irq_res = 109230424Shselasky bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); 110230424Shselasky if (sc->sc_otg.sc_irq_res == NULL) 111230424Shselasky goto error; 112230424Shselasky 113230424Shselasky sc->sc_otg.sc_bus.bdev = device_add_child(dev, "usbus", -1); 114230424Shselasky if (sc->sc_otg.sc_bus.bdev == NULL) 115230424Shselasky goto error; 116230424Shselasky 117230424Shselasky device_set_ivars(sc->sc_otg.sc_bus.bdev, &sc->sc_otg.sc_bus); 118230424Shselasky 119230424Shselasky err = bus_setup_intr(dev, sc->sc_otg.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 120266575Shselasky &dwc_otg_filter_interrupt, &dwc_otg_interrupt, sc, &sc->sc_otg.sc_intr_hdl); 121230424Shselasky if (err) { 122230424Shselasky sc->sc_otg.sc_intr_hdl = NULL; 123230424Shselasky goto error; 124230424Shselasky } 125230424Shselasky err = dwc_otg_init(&sc->sc_otg); 126230424Shselasky if (err == 0) { 127230424Shselasky err = device_probe_and_attach(sc->sc_otg.sc_bus.bdev); 128230424Shselasky } 129230424Shselasky if (err) 130230424Shselasky goto error; 131230424Shselasky return (0); 132230424Shselasky 133230424Shselaskyerror: 134230424Shselasky dwc_otg_detach(dev); 135230424Shselasky return (ENXIO); 136230424Shselasky} 137230424Shselasky 138230424Shselaskystatic int 139230424Shselaskydwc_otg_detach(device_t dev) 140230424Shselasky{ 141230424Shselasky struct dwc_otg_super_softc *sc = device_get_softc(dev); 142230424Shselasky device_t bdev; 143230424Shselasky int err; 144230424Shselasky 145230424Shselasky if (sc->sc_otg.sc_bus.bdev) { 146230424Shselasky bdev = sc->sc_otg.sc_bus.bdev; 147230424Shselasky device_detach(bdev); 148230424Shselasky device_delete_child(dev, bdev); 149230424Shselasky } 150230424Shselasky /* during module unload there are lots of children leftover */ 151230424Shselasky device_delete_children(dev); 152230424Shselasky 153230424Shselasky if (sc->sc_otg.sc_irq_res && sc->sc_otg.sc_intr_hdl) { 154230424Shselasky /* 155230424Shselasky * only call dwc_otg_uninit() after dwc_otg_init() 156230424Shselasky */ 157230424Shselasky dwc_otg_uninit(&sc->sc_otg); 158230424Shselasky 159230424Shselasky err = bus_teardown_intr(dev, sc->sc_otg.sc_irq_res, 160230424Shselasky sc->sc_otg.sc_intr_hdl); 161230424Shselasky sc->sc_otg.sc_intr_hdl = NULL; 162230424Shselasky } 163230424Shselasky /* free IRQ channel, if any */ 164230424Shselasky if (sc->sc_otg.sc_irq_res) { 165230424Shselasky bus_release_resource(dev, SYS_RES_IRQ, 0, 166230424Shselasky sc->sc_otg.sc_irq_res); 167230424Shselasky sc->sc_otg.sc_irq_res = NULL; 168230424Shselasky } 169230424Shselasky /* free memory resource, if any */ 170230424Shselasky if (sc->sc_otg.sc_io_res) { 171230424Shselasky bus_release_resource(dev, SYS_RES_MEMORY, 0, 172230424Shselasky sc->sc_otg.sc_io_res); 173230424Shselasky sc->sc_otg.sc_io_res = NULL; 174230424Shselasky } 175230424Shselasky usb_bus_mem_free_all(&sc->sc_otg.sc_bus, NULL); 176230424Shselasky 177230424Shselasky return (0); 178230424Shselasky} 179230424Shselasky 180230424Shselaskystatic device_method_t dwc_otg_methods[] = { 181230424Shselasky /* Device interface */ 182230424Shselasky DEVMETHOD(device_probe, dwc_otg_probe), 183230424Shselasky DEVMETHOD(device_attach, dwc_otg_attach), 184230424Shselasky DEVMETHOD(device_detach, dwc_otg_detach), 185230424Shselasky DEVMETHOD(device_suspend, bus_generic_suspend), 186230424Shselasky DEVMETHOD(device_resume, bus_generic_resume), 187230424Shselasky DEVMETHOD(device_shutdown, bus_generic_shutdown), 188230424Shselasky 189230424Shselasky DEVMETHOD_END 190230424Shselasky}; 191230424Shselasky 192230424Shselaskystatic driver_t dwc_otg_driver = { 193230424Shselasky .name = "dwc_otg", 194230424Shselasky .methods = dwc_otg_methods, 195230424Shselasky .size = sizeof(struct dwc_otg_super_softc), 196230424Shselasky}; 197230424Shselasky 198230424Shselaskystatic devclass_t dwc_otg_devclass; 199230424Shselasky 200230424ShselaskyDRIVER_MODULE(dwcotg, atmelarm, dwc_otg_driver, dwc_otg_devclass, 0, 0); 201230424ShselaskyMODULE_DEPEND(dwcotg, usb, 1, 1, 1); 202