1184610Salfred/*- 2184610Salfred * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. 3184610Salfred * 4184610Salfred * Redistribution and use in source and binary forms, with or without 5184610Salfred * modification, are permitted provided that the following conditions 6184610Salfred * are met: 7184610Salfred * 1. Redistributions of source code must retain the above copyright 8184610Salfred * notice, this list of conditions and the following disclaimer. 9184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 10184610Salfred * notice, this list of conditions and the following disclaimer in the 11184610Salfred * documentation and/or other materials provided with the distribution. 12184610Salfred * 13184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23184610Salfred * SUCH DAMAGE. 24184610Salfred */ 25184610Salfred 26227843Smarius#include <sys/cdefs.h> 27227843Smarius__FBSDID("$FreeBSD$"); 28227843Smarius 29194677Sthompsa#include <sys/stdint.h> 30194677Sthompsa#include <sys/stddef.h> 31194677Sthompsa#include <sys/param.h> 32194677Sthompsa#include <sys/queue.h> 33194677Sthompsa#include <sys/types.h> 34194677Sthompsa#include <sys/systm.h> 35194677Sthompsa#include <sys/kernel.h> 36194677Sthompsa#include <sys/bus.h> 37194677Sthompsa#include <sys/module.h> 38194677Sthompsa#include <sys/lock.h> 39194677Sthompsa#include <sys/mutex.h> 40194677Sthompsa#include <sys/condvar.h> 41194677Sthompsa#include <sys/sysctl.h> 42194677Sthompsa#include <sys/sx.h> 43194677Sthompsa#include <sys/unistd.h> 44194677Sthompsa#include <sys/callout.h> 45194677Sthompsa#include <sys/malloc.h> 46194677Sthompsa#include <sys/priv.h> 47194677Sthompsa 48188942Sthompsa#include <dev/usb/usb.h> 49194677Sthompsa#include <dev/usb/usbdi.h> 50184610Salfred 51188942Sthompsa#include <dev/usb/usb_core.h> 52188942Sthompsa#include <dev/usb/usb_busdma.h> 53188942Sthompsa#include <dev/usb/usb_process.h> 54188942Sthompsa#include <dev/usb/usb_util.h> 55184610Salfred 56188942Sthompsa#include <dev/usb/usb_controller.h> 57188942Sthompsa#include <dev/usb/usb_bus.h> 58189598Sthompsa#include <dev/usb/controller/musb_otg.h> 59184610Salfred 60184610Salfred#include <sys/rman.h> 61184610Salfred 62184610Salfredstatic device_probe_t musbotg_probe; 63184610Salfredstatic device_attach_t musbotg_attach; 64184610Salfredstatic device_detach_t musbotg_detach; 65184610Salfred 66184610Salfredstruct musbotg_super_softc { 67184610Salfred struct musbotg_softc sc_otg; /* must be first */ 68184610Salfred}; 69184610Salfred 70184610Salfredstatic void 71187175Sthompsamusbotg_vbus_poll(struct musbotg_super_softc *sc) 72184610Salfred{ 73184610Salfred uint8_t vbus_val = 1; /* fake VBUS on - TODO */ 74184610Salfred 75184610Salfred /* just forward it */ 76187175Sthompsa musbotg_vbus_interrupt(&sc->sc_otg, vbus_val); 77184610Salfred} 78184610Salfred 79184610Salfredstatic void 80184610Salfredmusbotg_clocks_on(void *arg) 81184610Salfred{ 82184610Salfred#if 0 83184610Salfred struct musbotg_super_softc *sc = arg; 84184610Salfred 85184610Salfred#endif 86184610Salfred} 87184610Salfred 88184610Salfredstatic void 89184610Salfredmusbotg_clocks_off(void *arg) 90184610Salfred{ 91184610Salfred#if 0 92184610Salfred struct musbotg_super_softc *sc = arg; 93184610Salfred 94184610Salfred#endif 95184610Salfred} 96184610Salfred 97252912Sgonzostatic void 98252912Sgonzomusbotg_wrapper_interrupt(void *arg) 99252912Sgonzo{ 100252912Sgonzo 101252912Sgonzo /* 102252912Sgonzo * Nothing to do. 103252912Sgonzo * Main driver takes care about everything 104252912Sgonzo */ 105252912Sgonzo musbotg_interrupt(arg, 0, 0, 0); 106252912Sgonzo} 107252912Sgonzo 108252912Sgonzostatic void 109252912Sgonzomusbotg_ep_int_set(struct musbotg_softc *sc, int ep, int on) 110252912Sgonzo{ 111252912Sgonzo /* 112252912Sgonzo * Nothing to do. 113252912Sgonzo * Main driver takes care about everything 114252912Sgonzo */ 115252912Sgonzo} 116252912Sgonzo 117184610Salfredstatic int 118184610Salfredmusbotg_probe(device_t dev) 119184610Salfred{ 120184610Salfred device_set_desc(dev, "MUSB OTG integrated USB controller"); 121184610Salfred return (0); 122184610Salfred} 123184610Salfred 124184610Salfredstatic int 125184610Salfredmusbotg_attach(device_t dev) 126184610Salfred{ 127184610Salfred struct musbotg_super_softc *sc = device_get_softc(dev); 128184610Salfred int err; 129184610Salfred int rid; 130184610Salfred 131184610Salfred /* setup MUSB OTG USB controller interface softc */ 132184610Salfred sc->sc_otg.sc_clocks_on = &musbotg_clocks_on; 133184610Salfred sc->sc_otg.sc_clocks_off = &musbotg_clocks_off; 134184610Salfred sc->sc_otg.sc_clocks_arg = sc; 135184610Salfred 136187170Sthompsa /* initialise some bus fields */ 137187170Sthompsa sc->sc_otg.sc_bus.parent = dev; 138187170Sthompsa sc->sc_otg.sc_bus.devices = sc->sc_otg.sc_devices; 139187170Sthompsa sc->sc_otg.sc_bus.devices_max = MUSB2_MAX_DEVICES; 140187170Sthompsa 141184610Salfred /* get all DMA memory */ 142194228Sthompsa if (usb_bus_mem_alloc_all(&sc->sc_otg.sc_bus, 143184610Salfred USB_GET_DMA_TAG(dev), NULL)) { 144184610Salfred return (ENOMEM); 145184610Salfred } 146184610Salfred rid = 0; 147184610Salfred sc->sc_otg.sc_io_res = 148184610Salfred bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 149184610Salfred 150184610Salfred if (!(sc->sc_otg.sc_io_res)) { 151184610Salfred err = ENOMEM; 152184610Salfred goto error; 153184610Salfred } 154184610Salfred sc->sc_otg.sc_io_tag = rman_get_bustag(sc->sc_otg.sc_io_res); 155184610Salfred sc->sc_otg.sc_io_hdl = rman_get_bushandle(sc->sc_otg.sc_io_res); 156184610Salfred sc->sc_otg.sc_io_size = rman_get_size(sc->sc_otg.sc_io_res); 157184610Salfred 158184610Salfred rid = 0; 159184610Salfred sc->sc_otg.sc_irq_res = 160184610Salfred bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); 161184610Salfred if (!(sc->sc_otg.sc_irq_res)) { 162184610Salfred goto error; 163184610Salfred } 164184610Salfred sc->sc_otg.sc_bus.bdev = device_add_child(dev, "usbus", -1); 165184610Salfred if (!(sc->sc_otg.sc_bus.bdev)) { 166184610Salfred goto error; 167184610Salfred } 168184610Salfred device_set_ivars(sc->sc_otg.sc_bus.bdev, &sc->sc_otg.sc_bus); 169184610Salfred 170252912Sgonzo sc->sc_otg.sc_id = 0; 171252912Sgonzo sc->sc_otg.sc_platform_data = sc; 172252912Sgonzo sc->sc_otg.sc_mode = MUSB2_DEVICE_MODE; 173252912Sgonzo 174184610Salfred#if (__FreeBSD_version >= 700031) 175184610Salfred err = bus_setup_intr(dev, sc->sc_otg.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 176252912Sgonzo NULL, (driver_intr_t *)musbotg_wrapper_interrupt, sc, &sc->sc_otg.sc_intr_hdl); 177184610Salfred#else 178184610Salfred err = bus_setup_intr(dev, sc->sc_otg.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 179252912Sgonzo (driver_intr_t *)musbotg_wrapper_interrupt, sc, &sc->sc_otg.sc_intr_hdl); 180184610Salfred#endif 181184610Salfred if (err) { 182184610Salfred sc->sc_otg.sc_intr_hdl = NULL; 183184610Salfred goto error; 184184610Salfred } 185184610Salfred err = musbotg_init(&sc->sc_otg); 186184610Salfred if (!err) { 187184610Salfred err = device_probe_and_attach(sc->sc_otg.sc_bus.bdev); 188184610Salfred } 189184610Salfred if (err) { 190184610Salfred goto error; 191184610Salfred } else { 192184610Salfred /* poll VBUS one time */ 193187175Sthompsa musbotg_vbus_poll(sc); 194184610Salfred } 195184610Salfred return (0); 196184610Salfred 197184610Salfrederror: 198184610Salfred musbotg_detach(dev); 199184610Salfred return (ENXIO); 200184610Salfred} 201184610Salfred 202184610Salfredstatic int 203184610Salfredmusbotg_detach(device_t dev) 204184610Salfred{ 205184610Salfred struct musbotg_super_softc *sc = device_get_softc(dev); 206184610Salfred device_t bdev; 207184610Salfred int err; 208184610Salfred 209184610Salfred if (sc->sc_otg.sc_bus.bdev) { 210184610Salfred bdev = sc->sc_otg.sc_bus.bdev; 211184610Salfred device_detach(bdev); 212184610Salfred device_delete_child(dev, bdev); 213184610Salfred } 214184610Salfred /* during module unload there are lots of children leftover */ 215227849Shselasky device_delete_children(dev); 216184610Salfred 217184610Salfred if (sc->sc_otg.sc_irq_res && sc->sc_otg.sc_intr_hdl) { 218184610Salfred /* 219184610Salfred * only call musbotg_uninit() after musbotg_init() 220184610Salfred */ 221184610Salfred musbotg_uninit(&sc->sc_otg); 222184610Salfred 223184610Salfred err = bus_teardown_intr(dev, sc->sc_otg.sc_irq_res, 224184610Salfred sc->sc_otg.sc_intr_hdl); 225184610Salfred sc->sc_otg.sc_intr_hdl = NULL; 226184610Salfred } 227184610Salfred /* free IRQ channel, if any */ 228184610Salfred if (sc->sc_otg.sc_irq_res) { 229184610Salfred bus_release_resource(dev, SYS_RES_IRQ, 0, 230184610Salfred sc->sc_otg.sc_irq_res); 231184610Salfred sc->sc_otg.sc_irq_res = NULL; 232184610Salfred } 233184610Salfred /* free memory resource, if any */ 234184610Salfred if (sc->sc_otg.sc_io_res) { 235184610Salfred bus_release_resource(dev, SYS_RES_MEMORY, 0, 236184610Salfred sc->sc_otg.sc_io_res); 237184610Salfred sc->sc_otg.sc_io_res = NULL; 238184610Salfred } 239194228Sthompsa usb_bus_mem_free_all(&sc->sc_otg.sc_bus, NULL); 240184610Salfred 241184610Salfred return (0); 242184610Salfred} 243184610Salfred 244184610Salfredstatic device_method_t musbotg_methods[] = { 245184610Salfred /* Device interface */ 246184610Salfred DEVMETHOD(device_probe, musbotg_probe), 247184610Salfred DEVMETHOD(device_attach, musbotg_attach), 248184610Salfred DEVMETHOD(device_detach, musbotg_detach), 249228483Shselasky DEVMETHOD(device_suspend, bus_generic_suspend), 250228483Shselasky DEVMETHOD(device_resume, bus_generic_resume), 251228483Shselasky DEVMETHOD(device_shutdown, bus_generic_shutdown), 252184610Salfred 253227843Smarius DEVMETHOD_END 254184610Salfred}; 255184610Salfred 256184610Salfredstatic driver_t musbotg_driver = { 257228483Shselasky .name = "musbotg", 258228483Shselasky .methods = musbotg_methods, 259228483Shselasky .size = sizeof(struct musbotg_super_softc), 260184610Salfred}; 261184610Salfred 262184610Salfredstatic devclass_t musbotg_devclass; 263184610Salfred 264184610SalfredDRIVER_MODULE(musbotg, atmelarm, musbotg_driver, musbotg_devclass, 0, 0); 265188942SthompsaMODULE_DEPEND(musbotg, usb, 1, 1, 1); 266