rt305x_dotg.c revision 278278
1#include <sys/cdefs.h> 2__FBSDID("$FreeBSD: stable/10/sys/mips/rt305x/rt305x_dotg.c 278278 2015-02-05 20:03:02Z hselasky $"); 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 sc->sc_dci.sc_bus.dma_bits = 32; 96 97 /* get all DMA memory */ 98 if (usb_bus_mem_alloc_all(&sc->sc_dci.sc_bus, 99 USB_GET_DMA_TAG(dev), NULL)) { 100 printf("No mem\n"); 101 return (ENOMEM); 102 } 103 sc->sc_dci.sc_mem_rid = 0; 104 sc->sc_dci.sc_mem_res = 105 bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_dci.sc_irq_rid, 106 RF_ACTIVE); 107 if (!(sc->sc_dci.sc_mem_res)) { 108 printf("Can`t alloc MEM\n"); 109 goto error; 110 } 111 sc->sc_dci.sc_bst = rman_get_bustag(sc->sc_dci.sc_mem_res); 112 sc->sc_dci.sc_bsh = rman_get_bushandle(sc->sc_dci.sc_mem_res); 113 114 sc->sc_dci.sc_irq_rid = 0; 115 sc->sc_dci.sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 116 &sc->sc_dci.sc_irq_rid, RF_SHAREABLE| RF_ACTIVE); 117 if (!(sc->sc_dci.sc_irq_res)) { 118 printf("Can`t alloc IRQ\n"); 119 goto error; 120 } 121 122 sc->sc_dci.sc_bus.bdev = device_add_child(dev, "usbus", -1); 123 if (!(sc->sc_dci.sc_bus.bdev)) { 124 printf("Can`t add usbus\n"); 125 goto error; 126 } 127 device_set_ivars(sc->sc_dci.sc_bus.bdev, &sc->sc_dci.sc_bus); 128 129#if (__FreeBSD_version >= 700031) 130 err = bus_setup_intr(dev, sc->sc_dci.sc_irq_res, 131 INTR_TYPE_BIO | INTR_MPSAFE, NULL, (driver_intr_t *)dotg_interrupt, 132 sc, &sc->sc_dci.sc_intr_hdl); 133#else 134 err = bus_setup_intr(dev, sc->sc_dci.sc_irq_res, 135 INTR_TYPE_BIO | INTR_MPSAFE, (driver_intr_t *)dotg_interrupt, 136 sc, &sc->sc_dci.sc_intr_hdl); 137#endif 138 if (err) { 139 sc->sc_dci.sc_intr_hdl = NULL; 140 printf("Can`t set IRQ handle\n"); 141 goto error; 142 } 143 144 /* Run clock for OTG core */ 145 rt305x_sysctl_set(SYSCTL_CLKCFG1, rt305x_sysctl_get(SYSCTL_CLKCFG1) | 146 SYSCTL_CLKCFG1_OTG_CLK_EN); 147 rt305x_sysctl_set(SYSCTL_RSTCTRL, SYSCTL_RSTCTRL_OTG); 148 DELAY(100); 149 150 err = dotg_init(&sc->sc_dci); 151 if (err) printf("dotg_init fail\n"); 152 if (!err) { 153 err = device_probe_and_attach(sc->sc_dci.sc_bus.bdev); 154 if (err) printf("device_probe_and_attach fail\n"); 155 } 156 if (err) { 157 goto error; 158 } 159 return (0); 160 161error: 162 dotg_obio_detach(dev); 163 return (ENXIO); 164} 165 166static int 167dotg_obio_detach(device_t dev) 168{ 169 struct dotg_obio_softc *sc = device_get_softc(dev); 170 device_t bdev; 171 int err; 172 173 if (sc->sc_dci.sc_bus.bdev) { 174 bdev = sc->sc_dci.sc_bus.bdev; 175 device_detach(bdev); 176 device_delete_child(dev, bdev); 177 } 178 /* during module unload there are lots of children leftover */ 179 device_delete_children(dev); 180 181 if (sc->sc_dci.sc_irq_res && sc->sc_dci.sc_intr_hdl) { 182 /* 183 * only call dotg_obio_uninit() after dotg_obio_init() 184 */ 185 dotg_uninit(&sc->sc_dci); 186 187 /* Stop OTG clock */ 188 rt305x_sysctl_set(SYSCTL_CLKCFG1, 189 rt305x_sysctl_get(SYSCTL_CLKCFG1) & 190 ~SYSCTL_CLKCFG1_OTG_CLK_EN); 191 192 err = bus_teardown_intr(dev, sc->sc_dci.sc_irq_res, 193 sc->sc_dci.sc_intr_hdl); 194 sc->sc_dci.sc_intr_hdl = NULL; 195 } 196 if (sc->sc_dci.sc_irq_res) { 197 bus_release_resource(dev, SYS_RES_IRQ, 0, 198 sc->sc_dci.sc_irq_res); 199 sc->sc_dci.sc_irq_res = NULL; 200 } 201 if (sc->sc_dci.sc_mem_res) { 202 bus_release_resource(dev, SYS_RES_MEMORY, 0, 203 sc->sc_dci.sc_mem_res); 204 sc->sc_dci.sc_mem_res = NULL; 205 } 206 usb_bus_mem_free_all(&sc->sc_dci.sc_bus, NULL); 207 208 return (0); 209} 210 211static device_method_t dotg_obio_methods[] = { 212 /* Device interface */ 213 DEVMETHOD(device_probe, dotg_obio_probe), 214 DEVMETHOD(device_attach, dotg_obio_attach), 215 DEVMETHOD(device_detach, dotg_obio_detach), 216 DEVMETHOD(device_suspend, bus_generic_suspend), 217 DEVMETHOD(device_resume, bus_generic_resume), 218 DEVMETHOD(device_shutdown, bus_generic_shutdown), 219 220 DEVMETHOD_END 221}; 222 223static driver_t dotg_obio_driver = { 224 .name = "dotg", 225 .methods = dotg_obio_methods, 226 .size = sizeof(struct dotg_obio_softc), 227}; 228 229static devclass_t dotg_obio_devclass; 230 231DRIVER_MODULE(dotg, obio, dotg_obio_driver, dotg_obio_devclass, 0, 0); 232