atmegadci_atmelarm.c revision 228483
1184610Salfred#include <sys/cdefs.h> 2184610Salfred__FBSDID("$FreeBSD: head/sys/dev/usb/controller/atmegadci_atmelarm.c 228483 2011-12-14 00:28:54Z hselasky $"); 3184610Salfred 4184610Salfred/*- 5184610Salfred * Copyright (c) 2009 Hans Petter Selasky. All rights reserved. 6184610Salfred * 7184610Salfred * Redistribution and use in source and binary forms, with or without 8184610Salfred * modification, are permitted provided that the following conditions 9184610Salfred * are met: 10184610Salfred * 1. Redistributions of source code must retain the above copyright 11184610Salfred * notice, this list of conditions and the following disclaimer. 12184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 13184610Salfred * notice, this list of conditions and the following disclaimer in the 14184610Salfred * documentation and/or other materials provided with the distribution. 15184610Salfred * 16184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26184610Salfred * SUCH DAMAGE. 27184610Salfred */ 28184610Salfred 29184610Salfred#include <sys/stdint.h> 30184610Salfred#include <sys/stddef.h> 31184610Salfred#include <sys/param.h> 32184610Salfred#include <sys/queue.h> 33184610Salfred#include <sys/types.h> 34184610Salfred#include <sys/systm.h> 35184610Salfred#include <sys/kernel.h> 36184610Salfred#include <sys/bus.h> 37184610Salfred#include <sys/module.h> 38184610Salfred#include <sys/lock.h> 39184610Salfred#include <sys/mutex.h> 40184610Salfred#include <sys/condvar.h> 41184610Salfred#include <sys/sysctl.h> 42184610Salfred#include <sys/sx.h> 43184610Salfred#include <sys/unistd.h> 44184610Salfred#include <sys/callout.h> 45184610Salfred#include <sys/malloc.h> 46184610Salfred#include <sys/priv.h> 47184610Salfred 48184610Salfred#include <dev/usb/usb.h> 49184610Salfred#include <dev/usb/usbdi.h> 50184610Salfred 51184610Salfred#include <dev/usb/usb_core.h> 52184610Salfred#include <dev/usb/usb_busdma.h> 53184610Salfred#include <dev/usb/usb_process.h> 54194677Sthompsa#include <dev/usb/usb_util.h> 55194677Sthompsa 56194677Sthompsa#include <dev/usb/usb_controller.h> 57194677Sthompsa#include <dev/usb/usb_bus.h> 58194677Sthompsa#include <dev/usb/controller/atmegadci.h> 59194677Sthompsa 60194677Sthompsa#include <sys/rman.h> 61194677Sthompsa 62194677Sthompsastatic device_probe_t atmegadci_probe; 63194677Sthompsastatic device_attach_t atmegadci_attach; 64194677Sthompsastatic device_detach_t atmegadci_detach; 65194677Sthompsa 66194677Sthompsastruct atmegadci_super_softc { 67194677Sthompsa struct atmegadci_softc sc_otg; /* must be first */ 68194677Sthompsa}; 69194677Sthompsa 70194677Sthompsastatic void 71194677Sthompsaatmegadci_clocks_on(struct usb_bus *bus) 72194677Sthompsa{ 73194677Sthompsa /* TODO */ 74188942Sthompsa} 75194677Sthompsa 76194677Sthompsastatic void 77188942Sthompsaatmegadci_clocks_off(struct usb_bus *bus) 78194677Sthompsa{ 79184610Salfred /* TODO */ 80194228Sthompsa} 81188942Sthompsa 82188942Sthompsastatic int 83184610Salfredatmegadci_probe(device_t dev) 84188942Sthompsa{ 85184610Salfred device_set_desc(dev, "ATMEL OTG integrated USB controller"); 86184610Salfred return (0); 87184610Salfred} 88184610Salfred 89184610Salfredstatic int 90184610Salfredatmegadci_attach(device_t dev) 91187259Sthompsa{ 92187259Sthompsa struct atmegadci_super_softc *sc = device_get_softc(dev); 93187259Sthompsa int err; 94188413Sthompsa int rid; 95187259Sthompsa 96187259Sthompsa /* setup MUSB OTG USB controller interface softc */ 97184610Salfred sc->sc_otg.sc_clocks_on = &atmegadci_clocks_on; 98192984Sthompsa sc->sc_otg.sc_clocks_off = &atmegadci_clocks_off; 99192984Sthompsa 100184610Salfred /* initialise some bus fields */ 101192984Sthompsa sc->sc_otg.sc_bus.parent = dev; 102192984Sthompsa sc->sc_otg.sc_bus.devices = sc->sc_otg.sc_devices; 103189265Sthompsa sc->sc_otg.sc_bus.devices_max = ATMEGA_MAX_DEVICES; 104184610Salfred 105184610Salfred /* get all DMA memory */ 106184610Salfred if (usb_bus_mem_alloc_all(&sc->sc_otg.sc_bus, 107184610Salfred USB_GET_DMA_TAG(dev), NULL)) { 108184610Salfred return (ENOMEM); 109184610Salfred } 110184610Salfred rid = 0; 111184610Salfred sc->sc_otg.sc_io_res = 112184610Salfred bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 113184610Salfred 114184610Salfred if (!(sc->sc_otg.sc_io_res)) { 115193045Sthompsa err = ENOMEM; 116193045Sthompsa goto error; 117184610Salfred } 118192984Sthompsa sc->sc_otg.sc_io_tag = rman_get_bustag(sc->sc_otg.sc_io_res); 119192984Sthompsa sc->sc_otg.sc_io_hdl = rman_get_bushandle(sc->sc_otg.sc_io_res); 120192984Sthompsa 121192984Sthompsa rid = 0; 122192984Sthompsa sc->sc_otg.sc_irq_res = 123192984Sthompsa bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); 124192984Sthompsa if (!(sc->sc_otg.sc_irq_res)) { 125184610Salfred goto error; 126192984Sthompsa } 127184610Salfred sc->sc_otg.sc_bus.bdev = device_add_child(dev, "usbus", -1); 128187259Sthompsa if (!(sc->sc_otg.sc_bus.bdev)) { 129184610Salfred goto error; 130184610Salfred } 131184610Salfred device_set_ivars(sc->sc_otg.sc_bus.bdev, &sc->sc_otg.sc_bus); 132190734Sthompsa 133190734Sthompsa err = bus_setup_intr(dev, sc->sc_otg.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 134190734Sthompsa NULL, (driver_intr_t *)atmegadci_interrupt, sc, &sc->sc_otg.sc_intr_hdl); 135184610Salfred if (err) { 136184610Salfred sc->sc_otg.sc_intr_hdl = NULL; 137187259Sthompsa goto error; 138184610Salfred } 139184610Salfred err = atmegadci_init(&sc->sc_otg); 140184610Salfred if (!err) { 141190734Sthompsa err = device_probe_and_attach(sc->sc_otg.sc_bus.bdev); 142190734Sthompsa } 143190734Sthompsa if (err) { 144184610Salfred goto error; 145184610Salfred } 146184610Salfred return (0); 147192984Sthompsa 148194228Sthompsaerror: 149194228Sthompsa atmegadci_detach(dev); 150194228Sthompsa return (ENXIO); 151194228Sthompsa} 152194228Sthompsa 153194228Sthompsastatic int 154194228Sthompsaatmegadci_detach(device_t dev) 155184610Salfred{ 156184610Salfred struct atmegadci_super_softc *sc = device_get_softc(dev); 157184610Salfred device_t bdev; 158184610Salfred int err; 159184610Salfred 160184610Salfred if (sc->sc_otg.sc_bus.bdev) { 161184610Salfred bdev = sc->sc_otg.sc_bus.bdev; 162192984Sthompsa device_detach(bdev); 163184610Salfred device_delete_child(dev, bdev); 164184610Salfred } 165184610Salfred /* during module unload there are lots of children leftover */ 166184610Salfred device_delete_children(dev); 167184610Salfred 168184610Salfred if (sc->sc_otg.sc_irq_res && sc->sc_otg.sc_intr_hdl) { 169184610Salfred /* 170184610Salfred * only call atmegadci_uninit() after atmegadci_init() 171184610Salfred */ 172184610Salfred atmegadci_uninit(&sc->sc_otg); 173184610Salfred 174184610Salfred err = bus_teardown_intr(dev, sc->sc_otg.sc_irq_res, 175184610Salfred sc->sc_otg.sc_intr_hdl); 176184610Salfred sc->sc_otg.sc_intr_hdl = NULL; 177184610Salfred } 178184610Salfred /* free IRQ channel, if any */ 179184610Salfred if (sc->sc_otg.sc_irq_res) { 180184610Salfred bus_release_resource(dev, SYS_RES_IRQ, 0, 181184610Salfred sc->sc_otg.sc_irq_res); 182184610Salfred sc->sc_otg.sc_irq_res = NULL; 183184610Salfred } 184184610Salfred /* free memory resource, if any */ 185184610Salfred if (sc->sc_otg.sc_io_res) { 186184610Salfred bus_release_resource(dev, SYS_RES_MEMORY, 0, 187184610Salfred sc->sc_otg.sc_io_res); 188184610Salfred sc->sc_otg.sc_io_res = NULL; 189184610Salfred } 190184610Salfred usb_bus_mem_free_all(&sc->sc_otg.sc_bus, NULL); 191184610Salfred 192184610Salfred return (0); 193184610Salfred} 194184610Salfred 195184610Salfredstatic device_method_t atmegadci_methods[] = { 196184610Salfred /* Device interface */ 197184610Salfred DEVMETHOD(device_probe, atmegadci_probe), 198184610Salfred DEVMETHOD(device_attach, atmegadci_attach), 199184610Salfred DEVMETHOD(device_detach, atmegadci_detach), 200184610Salfred DEVMETHOD(device_suspend, bus_generic_suspend), 201184610Salfred DEVMETHOD(device_resume, bus_generic_resume), 202184610Salfred DEVMETHOD(device_shutdown, bus_generic_shutdown), 203184610Salfred 204184610Salfred DEVMETHOD_END 205184610Salfred}; 206184610Salfred 207184610Salfredstatic driver_t atmegadci_driver = { 208184610Salfred .name = "atmegadci", 209184610Salfred .methods = atmegadci_methods, 210184610Salfred .size = sizeof(struct atmegadci_super_softc), 211184610Salfred}; 212184610Salfred 213184610Salfredstatic devclass_t atmegadci_devclass; 214184610Salfred 215184610SalfredDRIVER_MODULE(atmegadci, atmelarm, atmegadci_driver, atmegadci_devclass, 0, 0); 216184610SalfredMODULE_DEPEND(atmegadci, usb, 1, 1, 1); 217184610Salfred