musb_otg_atmelarm.c revision 228483
1/*- 2 * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26#include <sys/cdefs.h> 27__FBSDID("$FreeBSD: head/sys/dev/usb/controller/musb_otg_atmelarm.c 228483 2011-12-14 00:28:54Z hselasky $"); 28 29#include <sys/stdint.h> 30#include <sys/stddef.h> 31#include <sys/param.h> 32#include <sys/queue.h> 33#include <sys/types.h> 34#include <sys/systm.h> 35#include <sys/kernel.h> 36#include <sys/bus.h> 37#include <sys/module.h> 38#include <sys/lock.h> 39#include <sys/mutex.h> 40#include <sys/condvar.h> 41#include <sys/sysctl.h> 42#include <sys/sx.h> 43#include <sys/unistd.h> 44#include <sys/callout.h> 45#include <sys/malloc.h> 46#include <sys/priv.h> 47 48#include <dev/usb/usb.h> 49#include <dev/usb/usbdi.h> 50 51#include <dev/usb/usb_core.h> 52#include <dev/usb/usb_busdma.h> 53#include <dev/usb/usb_process.h> 54#include <dev/usb/usb_util.h> 55 56#include <dev/usb/usb_controller.h> 57#include <dev/usb/usb_bus.h> 58#include <dev/usb/controller/musb_otg.h> 59 60#include <sys/rman.h> 61 62static device_probe_t musbotg_probe; 63static device_attach_t musbotg_attach; 64static device_detach_t musbotg_detach; 65 66struct musbotg_super_softc { 67 struct musbotg_softc sc_otg; /* must be first */ 68}; 69 70static void 71musbotg_vbus_poll(struct musbotg_super_softc *sc) 72{ 73 uint8_t vbus_val = 1; /* fake VBUS on - TODO */ 74 75 /* just forward it */ 76 musbotg_vbus_interrupt(&sc->sc_otg, vbus_val); 77} 78 79static void 80musbotg_clocks_on(void *arg) 81{ 82#if 0 83 struct musbotg_super_softc *sc = arg; 84 85#endif 86} 87 88static void 89musbotg_clocks_off(void *arg) 90{ 91#if 0 92 struct musbotg_super_softc *sc = arg; 93 94#endif 95} 96 97static int 98musbotg_probe(device_t dev) 99{ 100 device_set_desc(dev, "MUSB OTG integrated USB controller"); 101 return (0); 102} 103 104static int 105musbotg_attach(device_t dev) 106{ 107 struct musbotg_super_softc *sc = device_get_softc(dev); 108 int err; 109 int rid; 110 111 /* setup MUSB OTG USB controller interface softc */ 112 sc->sc_otg.sc_clocks_on = &musbotg_clocks_on; 113 sc->sc_otg.sc_clocks_off = &musbotg_clocks_off; 114 sc->sc_otg.sc_clocks_arg = sc; 115 116 /* initialise some bus fields */ 117 sc->sc_otg.sc_bus.parent = dev; 118 sc->sc_otg.sc_bus.devices = sc->sc_otg.sc_devices; 119 sc->sc_otg.sc_bus.devices_max = MUSB2_MAX_DEVICES; 120 121 /* get all DMA memory */ 122 if (usb_bus_mem_alloc_all(&sc->sc_otg.sc_bus, 123 USB_GET_DMA_TAG(dev), NULL)) { 124 return (ENOMEM); 125 } 126 rid = 0; 127 sc->sc_otg.sc_io_res = 128 bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 129 130 if (!(sc->sc_otg.sc_io_res)) { 131 err = ENOMEM; 132 goto error; 133 } 134 sc->sc_otg.sc_io_tag = rman_get_bustag(sc->sc_otg.sc_io_res); 135 sc->sc_otg.sc_io_hdl = rman_get_bushandle(sc->sc_otg.sc_io_res); 136 sc->sc_otg.sc_io_size = rman_get_size(sc->sc_otg.sc_io_res); 137 138 rid = 0; 139 sc->sc_otg.sc_irq_res = 140 bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); 141 if (!(sc->sc_otg.sc_irq_res)) { 142 goto error; 143 } 144 sc->sc_otg.sc_bus.bdev = device_add_child(dev, "usbus", -1); 145 if (!(sc->sc_otg.sc_bus.bdev)) { 146 goto error; 147 } 148 device_set_ivars(sc->sc_otg.sc_bus.bdev, &sc->sc_otg.sc_bus); 149 150#if (__FreeBSD_version >= 700031) 151 err = bus_setup_intr(dev, sc->sc_otg.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 152 NULL, (driver_intr_t *)musbotg_interrupt, sc, &sc->sc_otg.sc_intr_hdl); 153#else 154 err = bus_setup_intr(dev, sc->sc_otg.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 155 (driver_intr_t *)musbotg_interrupt, sc, &sc->sc_otg.sc_intr_hdl); 156#endif 157 if (err) { 158 sc->sc_otg.sc_intr_hdl = NULL; 159 goto error; 160 } 161 err = musbotg_init(&sc->sc_otg); 162 if (!err) { 163 err = device_probe_and_attach(sc->sc_otg.sc_bus.bdev); 164 } 165 if (err) { 166 goto error; 167 } else { 168 /* poll VBUS one time */ 169 musbotg_vbus_poll(sc); 170 } 171 return (0); 172 173error: 174 musbotg_detach(dev); 175 return (ENXIO); 176} 177 178static int 179musbotg_detach(device_t dev) 180{ 181 struct musbotg_super_softc *sc = device_get_softc(dev); 182 device_t bdev; 183 int err; 184 185 if (sc->sc_otg.sc_bus.bdev) { 186 bdev = sc->sc_otg.sc_bus.bdev; 187 device_detach(bdev); 188 device_delete_child(dev, bdev); 189 } 190 /* during module unload there are lots of children leftover */ 191 device_delete_children(dev); 192 193 if (sc->sc_otg.sc_irq_res && sc->sc_otg.sc_intr_hdl) { 194 /* 195 * only call musbotg_uninit() after musbotg_init() 196 */ 197 musbotg_uninit(&sc->sc_otg); 198 199 err = bus_teardown_intr(dev, sc->sc_otg.sc_irq_res, 200 sc->sc_otg.sc_intr_hdl); 201 sc->sc_otg.sc_intr_hdl = NULL; 202 } 203 /* free IRQ channel, if any */ 204 if (sc->sc_otg.sc_irq_res) { 205 bus_release_resource(dev, SYS_RES_IRQ, 0, 206 sc->sc_otg.sc_irq_res); 207 sc->sc_otg.sc_irq_res = NULL; 208 } 209 /* free memory resource, if any */ 210 if (sc->sc_otg.sc_io_res) { 211 bus_release_resource(dev, SYS_RES_MEMORY, 0, 212 sc->sc_otg.sc_io_res); 213 sc->sc_otg.sc_io_res = NULL; 214 } 215 usb_bus_mem_free_all(&sc->sc_otg.sc_bus, NULL); 216 217 return (0); 218} 219 220static device_method_t musbotg_methods[] = { 221 /* Device interface */ 222 DEVMETHOD(device_probe, musbotg_probe), 223 DEVMETHOD(device_attach, musbotg_attach), 224 DEVMETHOD(device_detach, musbotg_detach), 225 DEVMETHOD(device_suspend, bus_generic_suspend), 226 DEVMETHOD(device_resume, bus_generic_resume), 227 DEVMETHOD(device_shutdown, bus_generic_shutdown), 228 229 DEVMETHOD_END 230}; 231 232static driver_t musbotg_driver = { 233 .name = "musbotg", 234 .methods = musbotg_methods, 235 .size = sizeof(struct musbotg_super_softc), 236}; 237 238static devclass_t musbotg_devclass; 239 240DRIVER_MODULE(musbotg, atmelarm, musbotg_driver, musbotg_devclass, 0, 0); 241MODULE_DEPEND(musbotg, usb, 1, 1, 1); 242