1#include <sys/cdefs.h> 2__FBSDID("$FreeBSD$"); 3 4/*- 5 * Copyright (c) 2010,2011 Aleksandr Rybalko. All rights reserved. 6 * Copyright (c) 2007-2008 Hans Petter Selasky. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30#include <sys/stdint.h> 31#include <sys/stddef.h> 32#include <sys/param.h> 33#include <sys/queue.h> 34#include <sys/types.h> 35#include <sys/systm.h> 36#include <sys/kernel.h> 37#include <sys/bus.h> 38#include <sys/module.h> 39#include <sys/lock.h> 40#include <sys/mutex.h> 41#include <sys/condvar.h> 42#include <sys/sysctl.h> 43#include <sys/sx.h> 44#include <sys/unistd.h> 45#include <sys/callout.h> 46#include <sys/malloc.h> 47#include <sys/priv.h> 48#include <sys/rman.h> 49 50#include <dev/usb/usb.h> 51#include <dev/usb/usbdi.h> 52 53#include <dev/usb/usb_core.h> 54#include <dev/usb/usb_busdma.h> 55#include <dev/usb/usb_process.h> 56#include <dev/usb/usb_util.h> 57 58#include <dev/usb/usb_controller.h> 59#include <dev/usb/usb_bus.h> 60 61#include <dev/usb/controller/dotg.h> 62#include <mips/rt305x/rt305xreg.h> 63#include <mips/rt305x/rt305x_sysctlvar.h> 64 65#define MEM_RID 0 66 67static device_probe_t dotg_obio_probe; 68static device_attach_t dotg_obio_attach; 69static device_detach_t dotg_obio_detach; 70 71struct dotg_obio_softc { 72 struct dotg_softc sc_dci; /* must be first */ 73}; 74 75static int 76dotg_obio_probe(device_t dev) 77{ 78 device_set_desc(dev, "DWC like USB OTG controller"); 79 return (0); 80} 81 82static int 83dotg_obio_attach(device_t dev) 84{ 85 struct dotg_obio_softc *sc = device_get_softc(dev); 86 int err; 87 88 /* setup controller interface softc */ 89 90 /* initialise some bus fields */ 91 sc->sc_dci.sc_dev = dev; 92 sc->sc_dci.sc_bus.parent = dev; 93 sc->sc_dci.sc_bus.devices = sc->sc_dci.sc_devices; 94 sc->sc_dci.sc_bus.devices_max = DOTG_MAX_DEVICES; 95 96 /* get all DMA memory */ 97 if (usb_bus_mem_alloc_all(&sc->sc_dci.sc_bus, 98 USB_GET_DMA_TAG(dev), NULL)) { 99 printf("No mem\n"); 100 return (ENOMEM); 101 } 102 sc->sc_dci.sc_mem_rid = 0; 103 sc->sc_dci.sc_mem_res = 104 bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_dci.sc_irq_rid, 105 RF_ACTIVE); 106 if (!(sc->sc_dci.sc_mem_res)) { 107 printf("Can`t alloc MEM\n"); 108 goto error; 109 } 110 sc->sc_dci.sc_bst = rman_get_bustag(sc->sc_dci.sc_mem_res); 111 sc->sc_dci.sc_bsh = rman_get_bushandle(sc->sc_dci.sc_mem_res); 112 113 sc->sc_dci.sc_irq_rid = 0; 114 sc->sc_dci.sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 115 &sc->sc_dci.sc_irq_rid, RF_SHAREABLE| RF_ACTIVE); 116 if (!(sc->sc_dci.sc_irq_res)) { 117 printf("Can`t alloc IRQ\n"); 118 goto error; 119 } 120 121 sc->sc_dci.sc_bus.bdev = device_add_child(dev, "usbus", -1); 122 if (!(sc->sc_dci.sc_bus.bdev)) { 123 printf("Can`t add usbus\n"); 124 goto error; 125 } 126 device_set_ivars(sc->sc_dci.sc_bus.bdev, &sc->sc_dci.sc_bus); 127 128#if (__FreeBSD_version >= 700031) 129 err = bus_setup_intr(dev, sc->sc_dci.sc_irq_res, 130 INTR_TYPE_BIO | INTR_MPSAFE, NULL, (driver_intr_t *)dotg_interrupt, 131 sc, &sc->sc_dci.sc_intr_hdl); 132#else 133 err = bus_setup_intr(dev, sc->sc_dci.sc_irq_res, 134 INTR_TYPE_BIO | INTR_MPSAFE, (driver_intr_t *)dotg_interrupt, 135 sc, &sc->sc_dci.sc_intr_hdl); 136#endif 137 if (err) { 138 sc->sc_dci.sc_intr_hdl = NULL; 139 printf("Can`t set IRQ handle\n"); 140 goto error; 141 } 142 143 /* Run clock for OTG core */ 144 rt305x_sysctl_set(SYSCTL_CLKCFG1, rt305x_sysctl_get(SYSCTL_CLKCFG1) | 145 SYSCTL_CLKCFG1_OTG_CLK_EN); 146 rt305x_sysctl_set(SYSCTL_RSTCTRL, SYSCTL_RSTCTRL_OTG); 147 DELAY(100); 148 149 err = dotg_init(&sc->sc_dci); 150 if (err) printf("dotg_init fail\n"); 151 if (!err) { 152 err = device_probe_and_attach(sc->sc_dci.sc_bus.bdev); 153 if (err) printf("device_probe_and_attach fail\n"); 154 } 155 if (err) { 156 goto error; 157 } 158 return (0); 159 160error: 161 dotg_obio_detach(dev); 162 return (ENXIO); 163} 164 165static int 166dotg_obio_detach(device_t dev) 167{ 168 struct dotg_obio_softc *sc = device_get_softc(dev); 169 device_t bdev; 170 int err; 171 172 if (sc->sc_dci.sc_bus.bdev) { 173 bdev = sc->sc_dci.sc_bus.bdev; 174 device_detach(bdev); 175 device_delete_child(dev, bdev); 176 } 177 /* during module unload there are lots of children leftover */ 178 device_delete_children(dev); 179 180 if (sc->sc_dci.sc_irq_res && sc->sc_dci.sc_intr_hdl) { 181 /* 182 * only call dotg_obio_uninit() after dotg_obio_init() 183 */ 184 dotg_uninit(&sc->sc_dci); 185 186 /* Stop OTG clock */ 187 rt305x_sysctl_set(SYSCTL_CLKCFG1, 188 rt305x_sysctl_get(SYSCTL_CLKCFG1) & 189 ~SYSCTL_CLKCFG1_OTG_CLK_EN); 190 191 err = bus_teardown_intr(dev, sc->sc_dci.sc_irq_res, 192 sc->sc_dci.sc_intr_hdl); 193 sc->sc_dci.sc_intr_hdl = NULL; 194 } 195 if (sc->sc_dci.sc_irq_res) { 196 bus_release_resource(dev, SYS_RES_IRQ, 0, 197 sc->sc_dci.sc_irq_res); 198 sc->sc_dci.sc_irq_res = NULL; 199 } 200 if (sc->sc_dci.sc_mem_res) { 201 bus_release_resource(dev, SYS_RES_MEMORY, 0, 202 sc->sc_dci.sc_mem_res); 203 sc->sc_dci.sc_mem_res = NULL; 204 } 205 usb_bus_mem_free_all(&sc->sc_dci.sc_bus, NULL); 206 207 return (0); 208} 209 210static device_method_t dotg_obio_methods[] = { 211 /* Device interface */ 212 DEVMETHOD(device_probe, dotg_obio_probe), 213 DEVMETHOD(device_attach, dotg_obio_attach), 214 DEVMETHOD(device_detach, dotg_obio_detach), 215 DEVMETHOD(device_suspend, bus_generic_suspend), 216 DEVMETHOD(device_resume, bus_generic_resume), 217 DEVMETHOD(device_shutdown, bus_generic_shutdown), 218 219 DEVMETHOD_END 220}; 221 222static driver_t dotg_obio_driver = { 223 .name = "dotg", 224 .methods = dotg_obio_methods, 225 .size = sizeof(struct dotg_obio_softc), 226}; 227 228static devclass_t dotg_obio_devclass; 229 230DRIVER_MODULE(dotg, obio, dotg_obio_driver, dotg_obio_devclass, 0, 0); 231