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