musb_otg_atmelarm.c revision 194677
1218885Sdim/* $FreeBSD: head/sys/dev/usb/controller/musb_otg_atmelarm.c 194677 2009-06-23 02:19:59Z thompsa $ */ 2218885Sdim/*- 3218885Sdim * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. 4218885Sdim * 5218885Sdim * Redistribution and use in source and binary forms, with or without 6218885Sdim * modification, are permitted provided that the following conditions 7218885Sdim * are met: 8218885Sdim * 1. Redistributions of source code must retain the above copyright 9218885Sdim * notice, this list of conditions and the following disclaimer. 10218885Sdim * 2. Redistributions in binary form must reproduce the above copyright 11218885Sdim * notice, this list of conditions and the following disclaimer in the 12218885Sdim * documentation and/or other materials provided with the distribution. 13218885Sdim * 14218885Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15218885Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16218885Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17218885Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18218885Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19218885Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20218885Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21218885Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22218885Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23218885Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24218885Sdim * SUCH DAMAGE. 25218885Sdim */ 26218885Sdim 27218885Sdim#include <sys/stdint.h> 28218885Sdim#include <sys/stddef.h> 29218885Sdim#include <sys/param.h> 30218885Sdim#include <sys/queue.h> 31218885Sdim#include <sys/types.h> 32218885Sdim#include <sys/systm.h> 33218885Sdim#include <sys/kernel.h> 34218885Sdim#include <sys/bus.h> 35218885Sdim#include <sys/linker_set.h> 36218885Sdim#include <sys/module.h> 37218885Sdim#include <sys/lock.h> 38218885Sdim#include <sys/mutex.h> 39218885Sdim#include <sys/condvar.h> 40218885Sdim#include <sys/sysctl.h> 41218885Sdim#include <sys/sx.h> 42218885Sdim#include <sys/unistd.h> 43218885Sdim#include <sys/callout.h> 44218885Sdim#include <sys/malloc.h> 45218885Sdim#include <sys/priv.h> 46218885Sdim 47218885Sdim#include <dev/usb/usb.h> 48218885Sdim#include <dev/usb/usbdi.h> 49218885Sdim 50218885Sdim#include <dev/usb/usb_core.h> 51218885Sdim#include <dev/usb/usb_busdma.h> 52218885Sdim#include <dev/usb/usb_process.h> 53218885Sdim#include <dev/usb/usb_util.h> 54218885Sdim 55218885Sdim#include <dev/usb/usb_controller.h> 56218885Sdim#include <dev/usb/usb_bus.h> 57218885Sdim#include <dev/usb/controller/musb_otg.h> 58218885Sdim 59218885Sdim#include <sys/rman.h> 60218885Sdim 61218885Sdimstatic device_probe_t musbotg_probe; 62218885Sdimstatic device_attach_t musbotg_attach; 63218885Sdimstatic device_detach_t musbotg_detach; 64218885Sdimstatic device_shutdown_t musbotg_shutdown; 65218885Sdim 66218885Sdimstruct musbotg_super_softc { 67218885Sdim struct musbotg_softc sc_otg; /* must be first */ 68218885Sdim}; 69218885Sdim 70218885Sdimstatic void 71218885Sdimmusbotg_vbus_poll(struct musbotg_super_softc *sc) 72218885Sdim{ 73218885Sdim uint8_t vbus_val = 1; /* fake VBUS on - TODO */ 74218885Sdim 75218885Sdim /* just forward it */ 76218885Sdim musbotg_vbus_interrupt(&sc->sc_otg, vbus_val); 77218885Sdim} 78218885Sdim 79218885Sdimstatic void 80218885Sdimmusbotg_clocks_on(void *arg) 81218885Sdim{ 82218885Sdim#if 0 83218885Sdim struct musbotg_super_softc *sc = arg; 84218885Sdim 85218885Sdim#endif 86218885Sdim} 87218885Sdim 88218885Sdimstatic void 89218885Sdimmusbotg_clocks_off(void *arg) 90218885Sdim{ 91218885Sdim#if 0 92218885Sdim struct musbotg_super_softc *sc = arg; 93218885Sdim 94218885Sdim#endif 95218885Sdim} 96218885Sdim 97218885Sdimstatic int 98218885Sdimmusbotg_probe(device_t dev) 99218885Sdim{ 100218885Sdim device_set_desc(dev, "MUSB OTG integrated USB controller"); 101218885Sdim return (0); 102218885Sdim} 103218885Sdim 104218885Sdimstatic int 105218885Sdimmusbotg_attach(device_t dev) 106218885Sdim{ 107218885Sdim struct musbotg_super_softc *sc = device_get_softc(dev); 108218885Sdim int err; 109221345Sdim int rid; 110218885Sdim 111218885Sdim /* setup MUSB OTG USB controller interface softc */ 112221345Sdim sc->sc_otg.sc_clocks_on = &musbotg_clocks_on; 113218885Sdim sc->sc_otg.sc_clocks_off = &musbotg_clocks_off; 114218885Sdim sc->sc_otg.sc_clocks_arg = sc; 115221345Sdim 116218885Sdim /* initialise some bus fields */ 117218885Sdim sc->sc_otg.sc_bus.parent = dev; 118218885Sdim sc->sc_otg.sc_bus.devices = sc->sc_otg.sc_devices; 119218885Sdim sc->sc_otg.sc_bus.devices_max = MUSB2_MAX_DEVICES; 120218885Sdim 121218885Sdim /* get all DMA memory */ 122218885Sdim if (usb_bus_mem_alloc_all(&sc->sc_otg.sc_bus, 123218885Sdim USB_GET_DMA_TAG(dev), NULL)) { 124218885Sdim return (ENOMEM); 125218885Sdim } 126218885Sdim rid = 0; 127218885Sdim sc->sc_otg.sc_io_res = 128218885Sdim bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 129218885Sdim 130218885Sdim if (!(sc->sc_otg.sc_io_res)) { 131218885Sdim err = ENOMEM; 132218885Sdim goto error; 133218885Sdim } 134218885Sdim sc->sc_otg.sc_io_tag = rman_get_bustag(sc->sc_otg.sc_io_res); 135218885Sdim sc->sc_otg.sc_io_hdl = rman_get_bushandle(sc->sc_otg.sc_io_res); 136218885Sdim sc->sc_otg.sc_io_size = rman_get_size(sc->sc_otg.sc_io_res); 137218885Sdim 138218885Sdim rid = 0; 139218885Sdim sc->sc_otg.sc_irq_res = 140218885Sdim bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); 141218885Sdim if (!(sc->sc_otg.sc_irq_res)) { 142218885Sdim goto error; 143221345Sdim } 144221345Sdim sc->sc_otg.sc_bus.bdev = device_add_child(dev, "usbus", -1); 145218885Sdim if (!(sc->sc_otg.sc_bus.bdev)) { 146218885Sdim goto error; 147218885Sdim } 148221345Sdim device_set_ivars(sc->sc_otg.sc_bus.bdev, &sc->sc_otg.sc_bus); 149221345Sdim 150218885Sdim#if (__FreeBSD_version >= 700031) 151218885Sdim err = bus_setup_intr(dev, sc->sc_otg.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 152218885Sdim NULL, (driver_intr_t *)musbotg_interrupt, sc, &sc->sc_otg.sc_intr_hdl); 153218885Sdim#else 154218885Sdim err = bus_setup_intr(dev, sc->sc_otg.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 155218885Sdim (driver_intr_t *)musbotg_interrupt, sc, &sc->sc_otg.sc_intr_hdl); 156218885Sdim#endif 157218885Sdim if (err) { 158218885Sdim sc->sc_otg.sc_intr_hdl = NULL; 159218885Sdim goto error; 160218885Sdim } 161218885Sdim err = musbotg_init(&sc->sc_otg); 162218885Sdim if (!err) { 163218885Sdim err = device_probe_and_attach(sc->sc_otg.sc_bus.bdev); 164218885Sdim } 165218885Sdim if (err) { 166218885Sdim goto error; 167218885Sdim } else { 168218885Sdim /* poll VBUS one time */ 169218885Sdim musbotg_vbus_poll(sc); 170218885Sdim } 171218885Sdim return (0); 172218885Sdim 173218885Sdimerror: 174218885Sdim musbotg_detach(dev); 175218885Sdim return (ENXIO); 176218885Sdim} 177218885Sdim 178218885Sdimstatic int 179218885Sdimmusbotg_detach(device_t dev) 180218885Sdim{ 181218885Sdim struct musbotg_super_softc *sc = device_get_softc(dev); 182218885Sdim device_t bdev; 183218885Sdim int err; 184218885Sdim 185218885Sdim if (sc->sc_otg.sc_bus.bdev) { 186218885Sdim bdev = sc->sc_otg.sc_bus.bdev; 187218885Sdim device_detach(bdev); 188218885Sdim device_delete_child(dev, bdev); 189218885Sdim } 190218885Sdim /* during module unload there are lots of children leftover */ 191218885Sdim device_delete_all_children(dev); 192218885Sdim 193218885Sdim if (sc->sc_otg.sc_irq_res && sc->sc_otg.sc_intr_hdl) { 194218885Sdim /* 195218885Sdim * only call musbotg_uninit() after musbotg_init() 196218885Sdim */ 197218885Sdim musbotg_uninit(&sc->sc_otg); 198218885Sdim 199218885Sdim err = bus_teardown_intr(dev, sc->sc_otg.sc_irq_res, 200221345Sdim sc->sc_otg.sc_intr_hdl); 201221345Sdim sc->sc_otg.sc_intr_hdl = NULL; 202218885Sdim } 203218885Sdim /* free IRQ channel, if any */ 204218885Sdim if (sc->sc_otg.sc_irq_res) { 205218885Sdim bus_release_resource(dev, SYS_RES_IRQ, 0, 206218885Sdim sc->sc_otg.sc_irq_res); 207218885Sdim sc->sc_otg.sc_irq_res = NULL; 208218885Sdim } 209218885Sdim /* free memory resource, if any */ 210218885Sdim if (sc->sc_otg.sc_io_res) { 211218885Sdim bus_release_resource(dev, SYS_RES_MEMORY, 0, 212218885Sdim sc->sc_otg.sc_io_res); 213218885Sdim sc->sc_otg.sc_io_res = NULL; 214218885Sdim } 215218885Sdim usb_bus_mem_free_all(&sc->sc_otg.sc_bus, NULL); 216218885Sdim 217218885Sdim return (0); 218218885Sdim} 219218885Sdim 220219077Sdimstatic int 221219077Sdimmusbotg_shutdown(device_t dev) 222219077Sdim{ 223219077Sdim struct musbotg_super_softc *sc = device_get_softc(dev); 224219077Sdim int err; 225219077Sdim 226219077Sdim err = bus_generic_shutdown(dev); 227218885Sdim if (err) 228218885Sdim return (err); 229218885Sdim 230218885Sdim musbotg_uninit(&sc->sc_otg); 231221345Sdim 232221345Sdim return (0); 233218885Sdim} 234218885Sdim 235218885Sdimstatic device_method_t musbotg_methods[] = { 236218885Sdim /* Device interface */ 237218885Sdim DEVMETHOD(device_probe, musbotg_probe), 238218885Sdim DEVMETHOD(device_attach, musbotg_attach), 239218885Sdim DEVMETHOD(device_detach, musbotg_detach), 240218885Sdim DEVMETHOD(device_shutdown, musbotg_shutdown), 241218885Sdim 242218885Sdim /* Bus interface */ 243218885Sdim DEVMETHOD(bus_print_child, bus_generic_print_child), 244218885Sdim 245218885Sdim {0, 0} 246218885Sdim}; 247218885Sdim 248218885Sdimstatic driver_t musbotg_driver = { 249218885Sdim "musbotg", 250218885Sdim musbotg_methods, 251218885Sdim sizeof(struct musbotg_super_softc), 252218885Sdim}; 253218885Sdim 254218885Sdimstatic devclass_t musbotg_devclass; 255218885Sdim 256218885SdimDRIVER_MODULE(musbotg, atmelarm, musbotg_driver, musbotg_devclass, 0, 0); 257218885SdimMODULE_DEPEND(musbotg, usb, 1, 1, 1); 258218885Sdim