xref: /freebsd-src/sys/arm/nvidia/tegra_ehci.c (revision 3ddaf8200bc90b1410755ebac7b5c979ea90a2f6)
1ef2ee5d0SMichal Meloun /*-
2ef2ee5d0SMichal Meloun  * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
3ef2ee5d0SMichal Meloun  * All rights reserved.
4ef2ee5d0SMichal Meloun  *
5ef2ee5d0SMichal Meloun  * Redistribution and use in source and binary forms, with or without
6ef2ee5d0SMichal Meloun  * modification, are permitted provided that the following conditions
7ef2ee5d0SMichal Meloun  * are met:
8ef2ee5d0SMichal Meloun  * 1. Redistributions of source code must retain the above copyright
9ef2ee5d0SMichal Meloun  *    notice, this list of conditions and the following disclaimer.
10ef2ee5d0SMichal Meloun  * 2. Redistributions in binary form must reproduce the above copyright
11ef2ee5d0SMichal Meloun  *    notice, this list of conditions and the following disclaimer in the
12ef2ee5d0SMichal Meloun  *    documentation and/or other materials provided with the distribution.
13ef2ee5d0SMichal Meloun  *
14ef2ee5d0SMichal Meloun  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15ef2ee5d0SMichal Meloun  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16ef2ee5d0SMichal Meloun  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17ef2ee5d0SMichal Meloun  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18ef2ee5d0SMichal Meloun  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19ef2ee5d0SMichal Meloun  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20ef2ee5d0SMichal Meloun  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21ef2ee5d0SMichal Meloun  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22ef2ee5d0SMichal Meloun  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23ef2ee5d0SMichal Meloun  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24ef2ee5d0SMichal Meloun  * SUCH DAMAGE.
25ef2ee5d0SMichal Meloun  */
26ef2ee5d0SMichal Meloun 
27ef2ee5d0SMichal Meloun #include <sys/cdefs.h>
28ef2ee5d0SMichal Meloun /*
29ef2ee5d0SMichal Meloun  * EHCI driver for Tegra SoCs.
30ef2ee5d0SMichal Meloun  */
31ef2ee5d0SMichal Meloun #include "opt_bus.h"
32ef2ee5d0SMichal Meloun #include "opt_platform.h"
33ef2ee5d0SMichal Meloun 
34ef2ee5d0SMichal Meloun #include <sys/param.h>
35ef2ee5d0SMichal Meloun #include <sys/systm.h>
36ef2ee5d0SMichal Meloun #include <sys/kernel.h>
37ef2ee5d0SMichal Meloun #include <sys/module.h>
38ef2ee5d0SMichal Meloun #include <sys/bus.h>
39ef2ee5d0SMichal Meloun #include <sys/condvar.h>
40ef2ee5d0SMichal Meloun #include <sys/rman.h>
41ef2ee5d0SMichal Meloun 
42ef2ee5d0SMichal Meloun #include <machine/bus.h>
43ef2ee5d0SMichal Meloun #include <machine/resource.h>
44ef2ee5d0SMichal Meloun 
45be82b3a0SEmmanuel Vadot #include <dev/clk/clk.h>
461f469a9fSEmmanuel Vadot #include <dev/hwreset/hwreset.h>
47950a6087SEmmanuel Vadot #include <dev/phy/phy.h>
48ef2ee5d0SMichal Meloun #include <dev/ofw/ofw_bus.h>
49ef2ee5d0SMichal Meloun #include <dev/ofw/ofw_bus_subr.h>
50ef2ee5d0SMichal Meloun #include <dev/usb/usb.h>
51ef2ee5d0SMichal Meloun #include <dev/usb/usbdi.h>
52ef2ee5d0SMichal Meloun #include <dev/usb/usb_busdma.h>
53ef2ee5d0SMichal Meloun #include <dev/usb/usb_process.h>
54ef2ee5d0SMichal Meloun #include <dev/usb/usb_controller.h>
55ef2ee5d0SMichal Meloun #include <dev/usb/usb_bus.h>
56ef2ee5d0SMichal Meloun #include <dev/usb/controller/ehci.h>
57ef2ee5d0SMichal Meloun #include <dev/usb/controller/ehcireg.h>
58ef2ee5d0SMichal Meloun 
59ef2ee5d0SMichal Meloun #include "usbdevs.h"
60ef2ee5d0SMichal Meloun 
61ef2ee5d0SMichal Meloun #define	TEGRA_EHCI_REG_OFF	0x100
62ef2ee5d0SMichal Meloun #define	TEGRA_EHCI_REG_SIZE	0x100
63ef2ee5d0SMichal Meloun 
64ef2ee5d0SMichal Meloun /* Compatible devices. */
65ef2ee5d0SMichal Meloun #define	TEGRA124_EHCI		1
66b9cbd68dSMichal Meloun #define	TEGRA210_EHCI		2
67ef2ee5d0SMichal Meloun static struct ofw_compat_data compat_data[] = {
68ef2ee5d0SMichal Meloun 	{"nvidia,tegra124-ehci",	(uintptr_t)TEGRA124_EHCI},
69b9cbd68dSMichal Meloun 	{"nvidia,tegra210-ehci",	(uintptr_t)TEGRA210_EHCI},
70ef2ee5d0SMichal Meloun 	{NULL,		 	0},
71ef2ee5d0SMichal Meloun };
72ef2ee5d0SMichal Meloun 
73ef2ee5d0SMichal Meloun struct tegra_ehci_softc {
74ef2ee5d0SMichal Meloun 	ehci_softc_t	ehci_softc;
75ef2ee5d0SMichal Meloun 	device_t	dev;
76ef2ee5d0SMichal Meloun 	struct resource	*ehci_mem_res;	/* EHCI core regs. */
77ef2ee5d0SMichal Meloun 	struct resource	*ehci_irq_res;	/* EHCI core IRQ. */
78ef2ee5d0SMichal Meloun 	int		usb_alloc_called;
79ef2ee5d0SMichal Meloun 	clk_t		clk;
80ef2ee5d0SMichal Meloun 	phy_t 		phy;
81ef2ee5d0SMichal Meloun 	hwreset_t 	reset;
82ef2ee5d0SMichal Meloun };
83ef2ee5d0SMichal Meloun 
84ef2ee5d0SMichal Meloun static void
85ef2ee5d0SMichal Meloun tegra_ehci_post_reset(struct ehci_softc *ehci_softc)
86ef2ee5d0SMichal Meloun {
87ef2ee5d0SMichal Meloun 	uint32_t usbmode;
88ef2ee5d0SMichal Meloun 
89ef2ee5d0SMichal Meloun 	/* Force HOST mode. */
90ef2ee5d0SMichal Meloun 	usbmode = EOREAD4(ehci_softc, EHCI_USBMODE_LPM);
91ef2ee5d0SMichal Meloun 	usbmode &= ~EHCI_UM_CM;
92ef2ee5d0SMichal Meloun 	usbmode |= EHCI_UM_CM_HOST;
93ef2ee5d0SMichal Meloun 	device_printf(ehci_softc->sc_bus.bdev, "set host controller mode\n");
94ef2ee5d0SMichal Meloun 	EOWRITE4(ehci_softc, EHCI_USBMODE_LPM, usbmode);
95ef2ee5d0SMichal Meloun }
96ef2ee5d0SMichal Meloun 
97ef2ee5d0SMichal Meloun static int
98ef2ee5d0SMichal Meloun tegra_ehci_probe(device_t dev)
99ef2ee5d0SMichal Meloun {
100ef2ee5d0SMichal Meloun 
101ef2ee5d0SMichal Meloun 	if (!ofw_bus_status_okay(dev))
102ef2ee5d0SMichal Meloun 		return (ENXIO);
103ef2ee5d0SMichal Meloun 
104ef2ee5d0SMichal Meloun 	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) {
105ef2ee5d0SMichal Meloun 		device_set_desc(dev, "Nvidia Tegra EHCI controller");
106ef2ee5d0SMichal Meloun 		return (BUS_PROBE_DEFAULT);
107ef2ee5d0SMichal Meloun 	}
108ef2ee5d0SMichal Meloun 	return (ENXIO);
109ef2ee5d0SMichal Meloun }
110ef2ee5d0SMichal Meloun 
111ef2ee5d0SMichal Meloun static int
112ef2ee5d0SMichal Meloun tegra_ehci_detach(device_t dev)
113ef2ee5d0SMichal Meloun {
114ef2ee5d0SMichal Meloun 	struct tegra_ehci_softc *sc;
115ef2ee5d0SMichal Meloun 	ehci_softc_t *esc;
116*3ddaf820SJohn Baldwin 	int error;
117*3ddaf820SJohn Baldwin 
118*3ddaf820SJohn Baldwin 	error = bus_generic_detach(dev);
119*3ddaf820SJohn Baldwin 	if (error != 0)
120*3ddaf820SJohn Baldwin 		return (error);
121ef2ee5d0SMichal Meloun 
122ef2ee5d0SMichal Meloun 	sc = device_get_softc(dev);
123ef2ee5d0SMichal Meloun 
124ef2ee5d0SMichal Meloun 	esc = &sc->ehci_softc;
125ef2ee5d0SMichal Meloun 	if (sc->clk != NULL)
126ef2ee5d0SMichal Meloun 		clk_release(sc->clk);
127ef2ee5d0SMichal Meloun 	if (esc->sc_flags & EHCI_SCFLG_DONEINIT)
128ef2ee5d0SMichal Meloun 		ehci_detach(esc);
129ef2ee5d0SMichal Meloun 	if (esc->sc_intr_hdl != NULL)
130ef2ee5d0SMichal Meloun 		bus_teardown_intr(dev, esc->sc_irq_res,
131ef2ee5d0SMichal Meloun 		    esc->sc_intr_hdl);
132ef2ee5d0SMichal Meloun 	if (sc->ehci_irq_res != NULL)
133ef2ee5d0SMichal Meloun 		bus_release_resource(dev, SYS_RES_IRQ, 0,
134ef2ee5d0SMichal Meloun 		    sc->ehci_irq_res);
135ef2ee5d0SMichal Meloun 	if (sc->ehci_mem_res != NULL)
136ef2ee5d0SMichal Meloun 		bus_release_resource(dev, SYS_RES_MEMORY, 0,
137ef2ee5d0SMichal Meloun 		    sc->ehci_mem_res);
138ef2ee5d0SMichal Meloun 	if (sc->usb_alloc_called)
139ef2ee5d0SMichal Meloun 		usb_bus_mem_free_all(&esc->sc_bus, &ehci_iterate_hw_softc);
140ef2ee5d0SMichal Meloun 
141ef2ee5d0SMichal Meloun 	return (0);
142ef2ee5d0SMichal Meloun }
143ef2ee5d0SMichal Meloun 
144ef2ee5d0SMichal Meloun static int
145ef2ee5d0SMichal Meloun tegra_ehci_attach(device_t dev)
146ef2ee5d0SMichal Meloun {
147ef2ee5d0SMichal Meloun 	struct tegra_ehci_softc *sc;
148ef2ee5d0SMichal Meloun 	ehci_softc_t *esc;
149ef2ee5d0SMichal Meloun 	int rv, rid;
150ef2ee5d0SMichal Meloun 	uint64_t freq;
151ef2ee5d0SMichal Meloun 
152ef2ee5d0SMichal Meloun 	sc = device_get_softc(dev);
153ef2ee5d0SMichal Meloun 	sc->dev = dev;
154ef2ee5d0SMichal Meloun 	esc = &sc->ehci_softc;
155ef2ee5d0SMichal Meloun 
156ef2ee5d0SMichal Meloun 	/* Allocate resources. */
157ef2ee5d0SMichal Meloun 	rid = 0;
158ef2ee5d0SMichal Meloun 	sc->ehci_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
159ef2ee5d0SMichal Meloun 	    RF_ACTIVE | RF_SHAREABLE);
160ef2ee5d0SMichal Meloun 	if (sc->ehci_mem_res == NULL) {
161ef2ee5d0SMichal Meloun 		device_printf(dev, "Cannot allocate memory resources\n");
162ef2ee5d0SMichal Meloun 		rv = ENXIO;
163ef2ee5d0SMichal Meloun 		goto out;
164ef2ee5d0SMichal Meloun 	}
165ef2ee5d0SMichal Meloun 
166ef2ee5d0SMichal Meloun 	rid = 0;
167ef2ee5d0SMichal Meloun 	sc->ehci_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
168ef2ee5d0SMichal Meloun 	    RF_ACTIVE);
169ef2ee5d0SMichal Meloun 	if (sc->ehci_irq_res == NULL) {
170ef2ee5d0SMichal Meloun 		device_printf(dev, "Cannot allocate IRQ resources\n");
171ef2ee5d0SMichal Meloun 		rv = ENXIO;
172ef2ee5d0SMichal Meloun 		goto out;
173ef2ee5d0SMichal Meloun 	}
174ef2ee5d0SMichal Meloun 
175dac93553SMichal Meloun 	rv = hwreset_get_by_ofw_name(dev, 0, "usb", &sc->reset);
176ef2ee5d0SMichal Meloun 	if (rv != 0) {
177ef2ee5d0SMichal Meloun 		device_printf(dev, "Cannot get reset\n");
178ef2ee5d0SMichal Meloun 		rv = ENXIO;
179ef2ee5d0SMichal Meloun 		goto out;
180ef2ee5d0SMichal Meloun 	}
181ef2ee5d0SMichal Meloun 
182dac93553SMichal Meloun 	rv = phy_get_by_ofw_property(sc->dev, 0, "nvidia,phy", &sc->phy);
183ef2ee5d0SMichal Meloun 	if (rv != 0) {
184ef2ee5d0SMichal Meloun 		device_printf(sc->dev, "Cannot get 'nvidia,phy' phy\n");
185ef2ee5d0SMichal Meloun 		rv = ENXIO;
186ef2ee5d0SMichal Meloun 		goto out;
187ef2ee5d0SMichal Meloun 	}
188ef2ee5d0SMichal Meloun 
189dac93553SMichal Meloun 	rv = clk_get_by_ofw_index(sc->dev, 0, 0, &sc->clk);
190ef2ee5d0SMichal Meloun 	if (rv != 0) {
191ef2ee5d0SMichal Meloun 		device_printf(dev, "Cannot get clock\n");
192ef2ee5d0SMichal Meloun 		goto out;
193ef2ee5d0SMichal Meloun 	}
194ef2ee5d0SMichal Meloun 
195ef2ee5d0SMichal Meloun 	rv = clk_enable(sc->clk);
196ef2ee5d0SMichal Meloun 	if (rv != 0) {
197ef2ee5d0SMichal Meloun 		device_printf(dev, "Cannot enable clock\n");
198ef2ee5d0SMichal Meloun 		goto out;
199ef2ee5d0SMichal Meloun 	}
200ef2ee5d0SMichal Meloun 
201ef2ee5d0SMichal Meloun 	freq = 0;
202ef2ee5d0SMichal Meloun 	rv = clk_get_freq(sc->clk, &freq);
203ef2ee5d0SMichal Meloun 	if (rv != 0) {
204ef2ee5d0SMichal Meloun 		device_printf(dev, "Cannot get clock frequency\n");
205ef2ee5d0SMichal Meloun 		goto out;
206ef2ee5d0SMichal Meloun 	}
207ef2ee5d0SMichal Meloun 
208ef2ee5d0SMichal Meloun 	rv = hwreset_deassert(sc->reset);
209ef2ee5d0SMichal Meloun 	if (rv != 0) {
210ef2ee5d0SMichal Meloun 		device_printf(dev, "Cannot clear reset: %d\n", rv);
211ef2ee5d0SMichal Meloun 		rv = ENXIO;
212ef2ee5d0SMichal Meloun 		goto out;
213ef2ee5d0SMichal Meloun 	}
214ef2ee5d0SMichal Meloun 
215f8759facSMichal Meloun 	rv = phy_enable(sc->phy);
216ef2ee5d0SMichal Meloun 	if (rv != 0) {
217ef2ee5d0SMichal Meloun 		device_printf(dev, "Cannot enable phy: %d\n", rv);
218ef2ee5d0SMichal Meloun 		goto out;
219ef2ee5d0SMichal Meloun 	}
220ef2ee5d0SMichal Meloun 
221ef2ee5d0SMichal Meloun 	/* Fill data for EHCI driver. */
222ef2ee5d0SMichal Meloun 	esc->sc_vendor_get_port_speed = ehci_get_port_speed_hostc;
223ef2ee5d0SMichal Meloun 	esc->sc_vendor_post_reset = tegra_ehci_post_reset;
224ef2ee5d0SMichal Meloun 	esc->sc_io_tag = rman_get_bustag(sc->ehci_mem_res);
225ef2ee5d0SMichal Meloun 	esc->sc_bus.parent = dev;
226ef2ee5d0SMichal Meloun 	esc->sc_bus.devices = esc->sc_devices;
227ef2ee5d0SMichal Meloun 	esc->sc_bus.devices_max = EHCI_MAX_DEVICES;
228ef2ee5d0SMichal Meloun 	esc->sc_bus.dma_bits = 32;
229ef2ee5d0SMichal Meloun 
230ef2ee5d0SMichal Meloun 	/* Allocate all DMA memory. */
231ef2ee5d0SMichal Meloun 	rv = usb_bus_mem_alloc_all(&esc->sc_bus, USB_GET_DMA_TAG(dev),
232ef2ee5d0SMichal Meloun 	    &ehci_iterate_hw_softc);
233ef2ee5d0SMichal Meloun 	sc->usb_alloc_called = 1;
234ef2ee5d0SMichal Meloun 	if (rv != 0) {
235ef2ee5d0SMichal Meloun 		device_printf(dev, "usb_bus_mem_alloc_all() failed\n");
236ef2ee5d0SMichal Meloun 		rv = ENOMEM;
237ef2ee5d0SMichal Meloun 		goto out;
238ef2ee5d0SMichal Meloun 	}
239ef2ee5d0SMichal Meloun 
240ef2ee5d0SMichal Meloun 	/*
241ef2ee5d0SMichal Meloun 	 * Set handle to USB related registers subregion used by
242ef2ee5d0SMichal Meloun 	 * generic EHCI driver.
243ef2ee5d0SMichal Meloun 	 */
244ef2ee5d0SMichal Meloun 	rv = bus_space_subregion(esc->sc_io_tag,
245ef2ee5d0SMichal Meloun 	    rman_get_bushandle(sc->ehci_mem_res),
246ef2ee5d0SMichal Meloun 	    TEGRA_EHCI_REG_OFF, TEGRA_EHCI_REG_SIZE, &esc->sc_io_hdl);
247ef2ee5d0SMichal Meloun 	if (rv != 0) {
248ef2ee5d0SMichal Meloun 		device_printf(dev, "Could not create USB memory subregion\n");
249ef2ee5d0SMichal Meloun 		rv = ENXIO;
250ef2ee5d0SMichal Meloun 		goto out;
251ef2ee5d0SMichal Meloun 	}
252ef2ee5d0SMichal Meloun 
253ef2ee5d0SMichal Meloun 	/* Setup interrupt handler. */
254c520cb4fSMichal Meloun 	rv = bus_setup_intr(dev, sc->ehci_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
255c520cb4fSMichal Meloun 	    NULL, (driver_intr_t *)ehci_interrupt, esc, &esc->sc_intr_hdl);
256ef2ee5d0SMichal Meloun 	if (rv != 0) {
257ef2ee5d0SMichal Meloun 		device_printf(dev, "Could not setup IRQ\n");
258ef2ee5d0SMichal Meloun 		goto out;
259ef2ee5d0SMichal Meloun 	}
260ef2ee5d0SMichal Meloun 
261ef2ee5d0SMichal Meloun 	/* Add USB bus device. */
2625b56413dSWarner Losh 	esc->sc_bus.bdev = device_add_child(dev, "usbus", DEVICE_UNIT_ANY);
263ef2ee5d0SMichal Meloun 	if (esc->sc_bus.bdev == NULL) {
264ef2ee5d0SMichal Meloun 		device_printf(dev, "Could not add USB device\n");
265ef2ee5d0SMichal Meloun 		goto out;
266ef2ee5d0SMichal Meloun 	}
267ef2ee5d0SMichal Meloun 	device_set_ivars(esc->sc_bus.bdev, &esc->sc_bus);
268ef2ee5d0SMichal Meloun 
269ef2ee5d0SMichal Meloun 	esc->sc_id_vendor = USB_VENDOR_FREESCALE;
270ef2ee5d0SMichal Meloun 	strlcpy(esc->sc_vendor, "Nvidia", sizeof(esc->sc_vendor));
271ef2ee5d0SMichal Meloun 
272ef2ee5d0SMichal Meloun 	/* Set flags that affect ehci_init() behavior. */
273ef2ee5d0SMichal Meloun 	esc->sc_flags |= EHCI_SCFLG_TT;
274ef2ee5d0SMichal Meloun 	esc->sc_flags |= EHCI_SCFLG_NORESTERM;
275ef2ee5d0SMichal Meloun 	rv = ehci_init(esc);
276ef2ee5d0SMichal Meloun 	if (rv != 0) {
277ef2ee5d0SMichal Meloun 		device_printf(dev, "USB init failed: %d\n",
278ef2ee5d0SMichal Meloun 		    rv);
279ef2ee5d0SMichal Meloun 		goto out;
280ef2ee5d0SMichal Meloun 	}
281ef2ee5d0SMichal Meloun 	esc->sc_flags |= EHCI_SCFLG_DONEINIT;
282ef2ee5d0SMichal Meloun 
283ef2ee5d0SMichal Meloun 	/* Probe the bus. */
284ef2ee5d0SMichal Meloun 	rv = device_probe_and_attach(esc->sc_bus.bdev);
285ef2ee5d0SMichal Meloun 	if (rv != 0) {
286ef2ee5d0SMichal Meloun 		device_printf(dev,
287ef2ee5d0SMichal Meloun 		    "device_probe_and_attach() failed\n");
288ef2ee5d0SMichal Meloun 		goto out;
289ef2ee5d0SMichal Meloun 	}
290ef2ee5d0SMichal Meloun 	return (0);
291ef2ee5d0SMichal Meloun 
292ef2ee5d0SMichal Meloun out:
293ef2ee5d0SMichal Meloun 	tegra_ehci_detach(dev);
294ef2ee5d0SMichal Meloun 	return (rv);
295ef2ee5d0SMichal Meloun }
296ef2ee5d0SMichal Meloun 
297ef2ee5d0SMichal Meloun static device_method_t ehci_methods[] = {
298ef2ee5d0SMichal Meloun 	/* Device interface */
299ef2ee5d0SMichal Meloun 	DEVMETHOD(device_probe, tegra_ehci_probe),
300ef2ee5d0SMichal Meloun 	DEVMETHOD(device_attach, tegra_ehci_attach),
301ef2ee5d0SMichal Meloun 	DEVMETHOD(device_detach, tegra_ehci_detach),
302ef2ee5d0SMichal Meloun 	DEVMETHOD(device_suspend, bus_generic_suspend),
303ef2ee5d0SMichal Meloun 	DEVMETHOD(device_resume, bus_generic_resume),
304ef2ee5d0SMichal Meloun 	DEVMETHOD(device_shutdown, bus_generic_shutdown),
305ef2ee5d0SMichal Meloun 
306ef2ee5d0SMichal Meloun 	/* Bus interface */
307ef2ee5d0SMichal Meloun 	DEVMETHOD(bus_print_child, bus_generic_print_child),
308ef2ee5d0SMichal Meloun 
309ef2ee5d0SMichal Meloun 	DEVMETHOD_END
310ef2ee5d0SMichal Meloun };
311ef2ee5d0SMichal Meloun 
3124bda238aSMichal Meloun static DEFINE_CLASS_0(ehci, ehci_driver, ehci_methods,
3134bda238aSMichal Meloun     sizeof(struct tegra_ehci_softc));
314289f133bSJohn Baldwin DRIVER_MODULE(tegra_ehci, simplebus, ehci_driver, NULL, NULL);
3154bda238aSMichal Meloun MODULE_DEPEND(tegra_ehci, usb, 1, 1, 1);
316