am335x_usbss.c revision 252913
11553Srgrimes/*- 21553Srgrimes * Copyright (c) 2013 Oleksandr Tymoshenko <gonzo@freebsd.org> 31553Srgrimes * 41553Srgrimes * Redistribution and use in source and binary forms, with or without 51553Srgrimes * modification, are permitted provided that the following conditions 61553Srgrimes * are met: 71553Srgrimes * 1. Redistributions of source code must retain the above copyright 81553Srgrimes * notice, this list of conditions and the following disclaimer. 91553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 101553Srgrimes * notice, this list of conditions and the following disclaimer in the 111553Srgrimes * documentation and/or other materials provided with the distribution. 121553Srgrimes * 131553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 141553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 151553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 161553Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 171553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 181553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 191553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 201553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 211553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 221553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 231553Srgrimes * SUCH DAMAGE. 241553Srgrimes */ 251553Srgrimes 261553Srgrimes#include <sys/cdefs.h> 271553Srgrimes__FBSDID("$FreeBSD: head/sys/arm/ti/am335x/am335x_usbss.c 252913 2013-07-07 04:22:08Z gonzo $"); 281553Srgrimes 291553Srgrimes#include <sys/stdint.h> 301553Srgrimes#include <sys/stddef.h> 311553Srgrimes#include <sys/param.h> 321553Srgrimes#include <sys/queue.h> 331553Srgrimes#include <sys/types.h> 341553Srgrimes#include <sys/systm.h> 3530642Scharnier#include <sys/kernel.h> 361553Srgrimes#include <sys/bus.h> 3730642Scharnier#include <sys/module.h> 3830642Scharnier#include <sys/lock.h> 3950479Speter#include <sys/mutex.h> 401553Srgrimes#include <sys/condvar.h> 411553Srgrimes#include <sys/sysctl.h> 421553Srgrimes#include <sys/sx.h> 431553Srgrimes#include <sys/unistd.h> 441553Srgrimes#include <sys/callout.h> 451553Srgrimes#include <sys/malloc.h> 461553Srgrimes#include <sys/priv.h> 471553Srgrimes 481553Srgrimes#include <dev/fdt/fdt_common.h> 491553Srgrimes#include <dev/ofw/openfirm.h> 501553Srgrimes#include <dev/ofw/ofw_bus.h> 511553Srgrimes#include <dev/ofw/ofw_bus_subr.h> 521553Srgrimes 531553Srgrimes#include <dev/usb/usb.h> 541553Srgrimes#include <dev/usb/usbdi.h> 551553Srgrimes 561553Srgrimes#include <dev/usb/usb_core.h> 571553Srgrimes#include <dev/usb/usb_busdma.h> 581553Srgrimes#include <dev/usb/usb_process.h> 591553Srgrimes#include <dev/usb/usb_util.h> 601553Srgrimes 611553Srgrimes#define USB_DEBUG_VAR usbssdebug 621553Srgrimes 631553Srgrimes#include <dev/usb/usb_controller.h> 641553Srgrimes#include <dev/usb/usb_bus.h> 651553Srgrimes#include <dev/usb/controller/musb_otg.h> 661553Srgrimes#include <dev/usb/usb_debug.h> 671553Srgrimes 681553Srgrimes#include <sys/rman.h> 691553Srgrimes 701553Srgrimes#include <arm/ti/ti_prcm.h> 711553Srgrimes#include <arm/ti/ti_scm.h> 721553Srgrimes#include <arm/ti/am335x/am335x_scm.h> 731553Srgrimes 741553Srgrimes#define AM335X_USB_PORTS 2 751553Srgrimes 761553Srgrimes#define USBSS_REVREG 0x00 771553Srgrimes#define USBSS_SYSCONFIG 0x10 781553Srgrimes#define USBSS_SYSCONFIG_SRESET 1 791553Srgrimes 801553Srgrimes#define USBCTRL_REV 0x00 811553Srgrimes#define USBCTRL_CTRL 0x14 821553Srgrimes#define USBCTRL_STAT 0x18 831553Srgrimes#define USBCTRL_IRQ_STAT0 0x30 841553Srgrimes#define IRQ_STAT0_RXSHIFT 16 851553Srgrimes#define IRQ_STAT0_TXSHIFT 0 861553Srgrimes#define USBCTRL_IRQ_STAT1 0x34 871553Srgrimes#define IRQ_STAT1_DRVVBUS (1 << 8) 881553Srgrimes#define USBCTRL_INTEN_SET0 0x38 89209344Sgavin#define USBCTRL_INTEN_SET1 0x3C 901553Srgrimes#define USBCTRL_INTEN_USB_ALL 0x1ff 911553Srgrimes#define USBCTRL_INTEN_USB_SOF (1 << 3) 921553Srgrimes#define USBCTRL_INTEN_CLR0 0x40 931553Srgrimes#define USBCTRL_INTEN_CLR1 0x44 941553Srgrimes#define USBCTRL_UTMI 0xE0 951553Srgrimes#define USBCTRL_UTMI_FSDATAEXT (1 << 1) 961553Srgrimes#define USBCTRL_MODE 0xE8 971553Srgrimes#define USBCTRL_MODE_IDDIG (1 << 8) 981553Srgrimes#define USBCTRL_MODE_IDDIGMUX (1 << 7) 991553Srgrimes 1001553Srgrimes/* USBSS resource + 2 MUSB ports */ 1018857Srgrimes 1021553Srgrimes#define RES_USBSS 0 1031553Srgrimes#define RES_USBCTRL(i) (3*i+1) 1041553Srgrimes#define RES_USBPHY(i) (3*i+2) 1051553Srgrimes#define RES_USBCORE(i) (3*i+3) 1061553Srgrimes 1071553Srgrimes#define USB_WRITE4(sc, idx, reg, val) do { \ 1081553Srgrimes bus_write_4((sc)->sc_mem_res[idx], (reg), (val)); \ 1091553Srgrimes} while (0) 1101553Srgrimes 1111553Srgrimes#define USB_READ4(sc, idx, reg) bus_read_4((sc)->sc_mem_res[idx], (reg)) 1121553Srgrimes 1131553Srgrimes#define USBSS_WRITE4(sc, reg, val) \ 1141553Srgrimes USB_WRITE4((sc), RES_USBSS, (reg), (val)) 1151553Srgrimes#define USBSS_READ4(sc, reg) \ 1161553Srgrimes USB_READ4((sc), RES_USBSS, (reg)) 1171553Srgrimes#define USBCTRL_WRITE4(sc, unit, reg, val) \ 1181553Srgrimes USB_WRITE4((sc), RES_USBCTRL(unit), (reg), (val)) 1191553Srgrimes#define USBCTRL_READ4(sc, unit, reg) \ 1201553Srgrimes USB_READ4((sc), RES_USBCTRL(unit), (reg)) 1211553Srgrimes#define USBPHY_WRITE4(sc, unit, reg, val) \ 1221553Srgrimes USB_WRITE4((sc), RES_USBPHY(unit), (reg), (val)) 1231553Srgrimes#define USBPHY_READ4(sc, unit, reg) \ 1241553Srgrimes USB_READ4((sc), RES_USBPHY(unit), (reg)) 1251553Srgrimes 1261553Srgrimesstatic struct resource_spec am335x_musbotg_mem_spec[] = { 1271553Srgrimes { SYS_RES_MEMORY, 0, RF_ACTIVE }, 1281553Srgrimes { SYS_RES_MEMORY, 1, RF_ACTIVE }, 1291553Srgrimes { SYS_RES_MEMORY, 2, RF_ACTIVE }, 1301553Srgrimes { SYS_RES_MEMORY, 3, RF_ACTIVE }, 1311553Srgrimes { SYS_RES_MEMORY, 4, RF_ACTIVE }, 1321553Srgrimes { SYS_RES_MEMORY, 5, RF_ACTIVE }, 1331553Srgrimes { SYS_RES_MEMORY, 6, RF_ACTIVE }, 1341553Srgrimes { -1, 0, 0 } 1351553Srgrimes}; 1361553Srgrimes 1371553Srgrimesstatic struct resource_spec am335x_musbotg_irq_spec[] = { 1381553Srgrimes { SYS_RES_IRQ, 0, RF_ACTIVE }, 1391553Srgrimes { SYS_RES_IRQ, 1, RF_ACTIVE }, 1401553Srgrimes { SYS_RES_IRQ, 2, RF_ACTIVE }, 1411553Srgrimes { -1, 0, 0 } 1421553Srgrimes}; 1431553Srgrimes 1441553Srgrimes#ifdef USB_DEBUG 1451553Srgrimesstatic int usbssdebug = 0; 1461553Srgrimes 1471553Srgrimesstatic SYSCTL_NODE(_hw_usb, OID_AUTO, am335x_usbss, CTLFLAG_RW, 0, "AM335x USBSS"); 1481553SrgrimesSYSCTL_INT(_hw_usb_am335x_usbss, OID_AUTO, debug, CTLFLAG_RW, 1491553Srgrimes &usbssdebug, 0, "Debug level"); 15030761Scharnier#endif 1514840Sbde 1521553Srgrimesstatic device_probe_t musbotg_probe; 1531553Srgrimesstatic device_attach_t musbotg_attach; 1541553Srgrimesstatic device_detach_t musbotg_detach; 1551553Srgrimes 1561553Srgrimesstruct musbotg_super_softc { 1571553Srgrimes struct musbotg_softc sc_otg[AM335X_USB_PORTS]; 1581553Srgrimes struct resource *sc_mem_res[AM335X_USB_PORTS*3+1]; 1591553Srgrimes struct resource *sc_irq_res[AM335X_USB_PORTS+1]; 1601553Srgrimes void *sc_intr_hdl; 1611553Srgrimes}; 1621553Srgrimes 1631553Srgrimesstatic void 1641553Srgrimesmusbotg_vbus_poll(struct musbotg_super_softc *sc, int port) 1651553Srgrimes{ 1661553Srgrimes uint32_t stat; 1671553Srgrimes 1681553Srgrimes if (sc->sc_otg[port].sc_mode == MUSB2_DEVICE_MODE) 1691553Srgrimes musbotg_vbus_interrupt(&sc->sc_otg[port], 1); 1701553Srgrimes else { 1711553Srgrimes stat = USBCTRL_READ4(sc, port, USBCTRL_STAT); 1721553Srgrimes musbotg_vbus_interrupt(&sc->sc_otg[port], stat & 1); 1731553Srgrimes } 1741553Srgrimes} 1751553Srgrimes 1761553Srgrimes/* 1771553Srgrimes * Arg to musbotg_clocks_on and musbot_clocks_off is 1781553Srgrimes * a uint32_t * pointing to the SCM register offset. 1791553Srgrimes */ 1801553Srgrimesstatic uint32_t USB_CTRL[] = {SCM_USB_CTRL0, SCM_USB_CTRL1}; 1811553Srgrimes 1821553Srgrimesstatic void 1831553Srgrimesmusbotg_clocks_on(void *arg) 1841553Srgrimes{ 1851553Srgrimes uint32_t c, reg = *(uint32_t *)arg; 1861553Srgrimes 1871553Srgrimes ti_scm_reg_read_4(reg, &c); 1881553Srgrimes c &= ~3; /* Enable power */ 1891553Srgrimes c |= 1 << 19; /* VBUS detect enable */ 1908857Srgrimes c |= 1 << 20; /* Session end enable */ 1911553Srgrimes ti_scm_reg_write_4(reg, c); 1921553Srgrimes} 1931553Srgrimes 1941553Srgrimesstatic void 1951553Srgrimesmusbotg_clocks_off(void *arg) 1961553Srgrimes{ 1971553Srgrimes uint32_t c, reg = *(uint32_t *)arg; 1981553Srgrimes 1991553Srgrimes /* Disable power to PHY */ 2001553Srgrimes ti_scm_reg_read_4(reg, &c); 2011553Srgrimes ti_scm_reg_write_4(reg, c | 3); 2021553Srgrimes} 2031553Srgrimes 2041553Srgrimesstatic void 2051553Srgrimesmusbotg_ep_int_set(struct musbotg_softc *sc, int ep, int on) 2061553Srgrimes{ 2071553Srgrimes struct musbotg_super_softc *ssc = sc->sc_platform_data; 2081553Srgrimes uint32_t epmask; 2091553Srgrimes 2101553Srgrimes epmask = ((1 << ep) << IRQ_STAT0_RXSHIFT); 2111553Srgrimes epmask |= ((1 << ep) << IRQ_STAT0_TXSHIFT); 2121553Srgrimes if (on) 2131553Srgrimes USBCTRL_WRITE4(ssc, sc->sc_id, 2141553Srgrimes USBCTRL_INTEN_SET0, epmask); 2151553Srgrimes else 2161553Srgrimes USBCTRL_WRITE4(ssc, sc->sc_id, 2171553Srgrimes USBCTRL_INTEN_CLR0, epmask); 2181553Srgrimes} 2191553Srgrimes 2201553Srgrimesstatic void 2211553Srgrimesmusbotg_usbss_interrupt(void *arg) 2221553Srgrimes{ 2231553Srgrimes panic("USBSS real interrupt"); 2241553Srgrimes} 2251553Srgrimes 2261553Srgrimesstatic void 2271553Srgrimesmusbotg_wrapper_interrupt(void *arg) 2281553Srgrimes{ 2291553Srgrimes struct musbotg_softc *sc = arg; 2301553Srgrimes struct musbotg_super_softc *ssc = sc->sc_platform_data; 2311553Srgrimes uint32_t stat, stat0, stat1; 2321553Srgrimes stat = USBCTRL_READ4(ssc, sc->sc_id, USBCTRL_STAT); 2331553Srgrimes stat0 = USBCTRL_READ4(ssc, sc->sc_id, USBCTRL_IRQ_STAT0); 2341553Srgrimes stat1 = USBCTRL_READ4(ssc, sc->sc_id, USBCTRL_IRQ_STAT1); 2351553Srgrimes if (stat0) 2361553Srgrimes USBCTRL_WRITE4(ssc, sc->sc_id, USBCTRL_IRQ_STAT0, stat0); 2371553Srgrimes if (stat1) 2381553Srgrimes USBCTRL_WRITE4(ssc, sc->sc_id, USBCTRL_IRQ_STAT1, stat1); 2391553Srgrimes 2401553Srgrimes DPRINTFN(4, "port%d: stat0=%08x stat1=%08x, stat=%08x\n", 2411553Srgrimes sc->sc_id, stat0, stat1, stat); 2421553Srgrimes 2431553Srgrimes if (stat1 & IRQ_STAT1_DRVVBUS) 2441553Srgrimes musbotg_vbus_interrupt(sc, stat & 1); 2451553Srgrimes 2461553Srgrimes musbotg_interrupt(arg, ((stat0 >> 16) & 0xffff), 2471553Srgrimes stat0 & 0xffff, stat1 & 0xff); 2481553Srgrimes} 2491553Srgrimes 2501553Srgrimesstatic int 2511553Srgrimesmusbotg_probe(device_t dev) 2521553Srgrimes{ 2531553Srgrimes if (!ofw_bus_is_compatible(dev, "ti,musb-am33xx")) 2541553Srgrimes return (ENXIO); 2551553Srgrimes 2561553Srgrimes device_set_desc(dev, "TI AM33xx integrated USB OTG controller"); 2571553Srgrimes 2581553Srgrimes return (BUS_PROBE_DEFAULT); 2591553Srgrimes} 2601553Srgrimes 2611553Srgrimesstatic int 2621553Srgrimesmusbotg_attach(device_t dev) 2631553Srgrimes{ 2641553Srgrimes struct musbotg_super_softc *sc = device_get_softc(dev); 2651553Srgrimes int err; 2661553Srgrimes int i; 2671553Srgrimes uint32_t rev, reg; 2681553Srgrimes 2691553Srgrimes /* Request the memory resources */ 2701553Srgrimes err = bus_alloc_resources(dev, am335x_musbotg_mem_spec, 2711553Srgrimes sc->sc_mem_res); 2721553Srgrimes if (err) { 27330642Scharnier device_printf(dev, 2741553Srgrimes "Error: could not allocate mem resources\n"); 2751553Srgrimes return (ENXIO); 2761553Srgrimes } 2771553Srgrimes 2781553Srgrimes /* Request the IRQ resources */ 2791553Srgrimes err = bus_alloc_resources(dev, am335x_musbotg_irq_spec, 2801553Srgrimes sc->sc_irq_res); 2811553Srgrimes if (err) { 2821553Srgrimes device_printf(dev, 2831553Srgrimes "Error: could not allocate irq resources\n"); 2841553Srgrimes return (ENXIO); 2851553Srgrimes } 2861553Srgrimes 2871553Srgrimes /* 2881553Srgrimes * Reset USBSS, USB0 and USB1 2891553Srgrimes */ 2901553Srgrimes rev = USBSS_READ4(sc, USBSS_REVREG); 2911553Srgrimes device_printf(dev, "TI AM335X USBSS v%d.%d.%d\n", 2921553Srgrimes (rev >> 8) & 7, (rev >> 6) & 3, rev & 63); 2931553Srgrimes 2941553Srgrimes ti_prcm_clk_enable(MUSB0_CLK); 2951553Srgrimes 2961553Srgrimes USBSS_WRITE4(sc, USBSS_SYSCONFIG, 2971553Srgrimes USBSS_SYSCONFIG_SRESET); 2981553Srgrimes while (USBSS_READ4(sc, USBSS_SYSCONFIG) & 2991553Srgrimes USBSS_SYSCONFIG_SRESET) 3001553Srgrimes ; 3011553Srgrimes 3021553Srgrimes err = bus_setup_intr(dev, sc->sc_irq_res[0], 3031553Srgrimes INTR_TYPE_BIO | INTR_MPSAFE, 3041553Srgrimes NULL, (driver_intr_t *)musbotg_usbss_interrupt, sc, 3051553Srgrimes &sc->sc_intr_hdl); 3061553Srgrimes 3071553Srgrimes if (err) { 3081553Srgrimes sc->sc_intr_hdl = NULL; 3091553Srgrimes device_printf(dev, "Failed to setup USBSS interrupt\n"); 3101553Srgrimes goto error; 3111553Srgrimes } 3121553Srgrimes 3131553Srgrimes for (i = 0; i < AM335X_USB_PORTS; i++) { 3141553Srgrimes /* setup MUSB OTG USB controller interface softc */ 3151553Srgrimes sc->sc_otg[i].sc_clocks_on = &musbotg_clocks_on; 3161553Srgrimes sc->sc_otg[i].sc_clocks_off = &musbotg_clocks_off; 3171553Srgrimes sc->sc_otg[i].sc_clocks_arg = &USB_CTRL[i]; 3181553Srgrimes 3191553Srgrimes sc->sc_otg[i].sc_ep_int_set = musbotg_ep_int_set; 3201553Srgrimes 3211553Srgrimes /* initialise some bus fields */ 3221553Srgrimes sc->sc_otg[i].sc_bus.parent = dev; 3231553Srgrimes sc->sc_otg[i].sc_bus.devices = sc->sc_otg[i].sc_devices; 3241553Srgrimes sc->sc_otg[i].sc_bus.devices_max = MUSB2_MAX_DEVICES; 3251553Srgrimes 3261553Srgrimes /* get all DMA memory */ 3271553Srgrimes if (usb_bus_mem_alloc_all(&sc->sc_otg[i].sc_bus, 3281553Srgrimes USB_GET_DMA_TAG(dev), NULL)) { 3291553Srgrimes device_printf(dev, 3301553Srgrimes "Failed allocate bus mem for musb%d\n", i); 3311553Srgrimes return (ENOMEM); 3321553Srgrimes } 3331553Srgrimes sc->sc_otg[i].sc_io_res = sc->sc_mem_res[RES_USBCORE(i)]; 3341553Srgrimes sc->sc_otg[i].sc_io_tag = 3351553Srgrimes rman_get_bustag(sc->sc_otg[i].sc_io_res); 3361553Srgrimes sc->sc_otg[i].sc_io_hdl = 3371553Srgrimes rman_get_bushandle(sc->sc_otg[i].sc_io_res); 3381553Srgrimes sc->sc_otg[i].sc_io_size = 3391553Srgrimes rman_get_size(sc->sc_otg[i].sc_io_res); 3401553Srgrimes 3411553Srgrimes sc->sc_otg[i].sc_irq_res = sc->sc_irq_res[i+1]; 3421553Srgrimes 3431553Srgrimes sc->sc_otg[i].sc_bus.bdev = device_add_child(dev, "usbus", -1); 3441553Srgrimes if (!(sc->sc_otg[i].sc_bus.bdev)) { 3451553Srgrimes device_printf(dev, "No busdev for musb%d\n", i); 3461553Srgrimes goto error; 347 } 348 device_set_ivars(sc->sc_otg[i].sc_bus.bdev, 349 &sc->sc_otg[i].sc_bus); 350 351 err = bus_setup_intr(dev, sc->sc_otg[i].sc_irq_res, 352 INTR_TYPE_BIO | INTR_MPSAFE, 353 NULL, (driver_intr_t *)musbotg_wrapper_interrupt, 354 &sc->sc_otg[i], &sc->sc_otg[i].sc_intr_hdl); 355 if (err) { 356 sc->sc_otg[i].sc_intr_hdl = NULL; 357 device_printf(dev, 358 "Failed to setup interrupt for musb%d\n", i); 359 goto error; 360 } 361 362 sc->sc_otg[i].sc_id = i; 363 sc->sc_otg[i].sc_platform_data = sc; 364 if (i == 0) 365 sc->sc_otg[i].sc_mode = MUSB2_DEVICE_MODE; 366 else 367 sc->sc_otg[i].sc_mode = MUSB2_HOST_MODE; 368 369 /* 370 * software-controlled function 371 */ 372 373 if (sc->sc_otg[i].sc_mode == MUSB2_HOST_MODE) { 374 reg = USBCTRL_READ4(sc, i, USBCTRL_MODE); 375 reg |= USBCTRL_MODE_IDDIGMUX; 376 reg &= ~USBCTRL_MODE_IDDIG; 377 USBCTRL_WRITE4(sc, i, USBCTRL_MODE, reg); 378 USBCTRL_WRITE4(sc, i, USBCTRL_UTMI, 379 USBCTRL_UTMI_FSDATAEXT); 380 } else { 381 reg = USBCTRL_READ4(sc, i, USBCTRL_MODE); 382 reg |= USBCTRL_MODE_IDDIGMUX; 383 reg |= USBCTRL_MODE_IDDIG; 384 USBCTRL_WRITE4(sc, i, USBCTRL_MODE, reg); 385 } 386 387 reg = USBCTRL_INTEN_USB_ALL & ~USBCTRL_INTEN_USB_SOF; 388 USBCTRL_WRITE4(sc, i, USBCTRL_INTEN_SET1, reg); 389 USBCTRL_WRITE4(sc, i, USBCTRL_INTEN_CLR0, 0xffffffff); 390 391 err = musbotg_init(&sc->sc_otg[i]); 392 if (!err) 393 err = device_probe_and_attach(sc->sc_otg[i].sc_bus.bdev); 394 395 if (err) 396 goto error; 397 398 /* poll VBUS one time */ 399 musbotg_vbus_poll(sc, i); 400 } 401 402 return (0); 403 404error: 405 musbotg_detach(dev); 406 return (ENXIO); 407} 408 409static int 410musbotg_detach(device_t dev) 411{ 412 struct musbotg_super_softc *sc = device_get_softc(dev); 413 device_t bdev; 414 int err; 415 int i; 416 417 for (i = 0; i < AM335X_USB_PORTS; i++) { 418 if (sc->sc_otg[i].sc_bus.bdev) { 419 bdev = sc->sc_otg[i].sc_bus.bdev; 420 device_detach(bdev); 421 device_delete_child(dev, bdev); 422 } 423 424 if (sc->sc_otg[i].sc_irq_res && sc->sc_otg[i].sc_intr_hdl) { 425 /* 426 * only call musbotg_uninit() after musbotg_init() 427 */ 428 musbotg_uninit(&sc->sc_otg[i]); 429 430 err = bus_teardown_intr(dev, sc->sc_otg[i].sc_irq_res, 431 sc->sc_otg[i].sc_intr_hdl); 432 sc->sc_otg[i].sc_intr_hdl = NULL; 433 } 434 435 usb_bus_mem_free_all(&sc->sc_otg[i].sc_bus, NULL); 436 } 437 438 if (sc->sc_intr_hdl) { 439 bus_teardown_intr(dev, sc->sc_irq_res[0], 440 sc->sc_intr_hdl); 441 sc->sc_intr_hdl = NULL; 442 } 443 444 445 /* Free resources if any */ 446 if (sc->sc_mem_res[0]) 447 bus_release_resources(dev, am335x_musbotg_mem_spec, 448 sc->sc_mem_res); 449 450 if (sc->sc_irq_res[0]) 451 bus_release_resources(dev, am335x_musbotg_irq_spec, 452 sc->sc_irq_res); 453 454 /* during module unload there are lots of children leftover */ 455 device_delete_children(dev); 456 457 return (0); 458} 459 460static device_method_t musbotg_methods[] = { 461 /* Device interface */ 462 DEVMETHOD(device_probe, musbotg_probe), 463 DEVMETHOD(device_attach, musbotg_attach), 464 DEVMETHOD(device_detach, musbotg_detach), 465 DEVMETHOD(device_suspend, bus_generic_suspend), 466 DEVMETHOD(device_resume, bus_generic_resume), 467 DEVMETHOD(device_shutdown, bus_generic_shutdown), 468 469 DEVMETHOD_END 470}; 471 472static driver_t musbotg_driver = { 473 .name = "musbotg", 474 .methods = musbotg_methods, 475 .size = sizeof(struct musbotg_super_softc), 476}; 477 478static devclass_t musbotg_devclass; 479 480DRIVER_MODULE(musbotg, simplebus, musbotg_driver, musbotg_devclass, 0, 0); 481MODULE_DEPEND(musbotg, usb, 1, 1, 1); 482