xref: /freebsd-src/sys/dev/usb/controller/dwc_otg_acpi.c (revision 3ddaf8200bc90b1410755ebac7b5c979ea90a2f6)
1518da7acSAndrew Turner /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3518da7acSAndrew Turner  *
4518da7acSAndrew Turner  * Copyright (c) 2012 Hans Petter Selasky.
5518da7acSAndrew Turner  *
6518da7acSAndrew Turner  * Redistribution and use in source and binary forms, with or without
7518da7acSAndrew Turner  * modification, are permitted provided that the following conditions
8518da7acSAndrew Turner  * are met:
9518da7acSAndrew Turner  * 1. Redistributions of source code must retain the above copyright
10518da7acSAndrew Turner  *    notice, this list of conditions and the following disclaimer.
11518da7acSAndrew Turner  * 2. Redistributions in binary form must reproduce the above copyright
12518da7acSAndrew Turner  *    notice, this list of conditions and the following disclaimer in the
13518da7acSAndrew Turner  *    documentation and/or other materials provided with the distribution.
14518da7acSAndrew Turner  *
15518da7acSAndrew Turner  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16518da7acSAndrew Turner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17518da7acSAndrew Turner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18518da7acSAndrew Turner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19518da7acSAndrew Turner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20518da7acSAndrew Turner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21518da7acSAndrew Turner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22518da7acSAndrew Turner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23518da7acSAndrew Turner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24518da7acSAndrew Turner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25518da7acSAndrew Turner  * SUCH DAMAGE.
26518da7acSAndrew Turner  */
27518da7acSAndrew Turner 
28518da7acSAndrew Turner #include <sys/cdefs.h>
29518da7acSAndrew Turner #include "opt_acpi.h"
30518da7acSAndrew Turner 
31518da7acSAndrew Turner #include <sys/param.h>
32518da7acSAndrew Turner #include <sys/systm.h>
33518da7acSAndrew Turner #include <sys/bus.h>
34518da7acSAndrew Turner #include <sys/condvar.h>
35518da7acSAndrew Turner #include <sys/kernel.h>
36518da7acSAndrew Turner #include <sys/lock.h>
37518da7acSAndrew Turner #include <sys/malloc.h>
38518da7acSAndrew Turner #include <sys/module.h>
39518da7acSAndrew Turner #include <sys/mutex.h>
40518da7acSAndrew Turner #include <sys/rman.h>
41518da7acSAndrew Turner 
42518da7acSAndrew Turner #include <contrib/dev/acpica/include/acpi.h>
43518da7acSAndrew Turner #include <contrib/dev/acpica/include/accommon.h>
44518da7acSAndrew Turner 
45518da7acSAndrew Turner #include <dev/acpica/acpivar.h>
46518da7acSAndrew Turner 
47518da7acSAndrew Turner #include <dev/usb/usb.h>
48518da7acSAndrew Turner #include <dev/usb/usbdi.h>
49518da7acSAndrew Turner 
50518da7acSAndrew Turner #include <dev/usb/usb_core.h>
51518da7acSAndrew Turner #include <dev/usb/usb_busdma.h>
52518da7acSAndrew Turner #include <dev/usb/usb_process.h>
53518da7acSAndrew Turner #include <dev/usb/usb_util.h>
54518da7acSAndrew Turner 
55518da7acSAndrew Turner #include <dev/usb/usb_controller.h>
56518da7acSAndrew Turner #include <dev/usb/usb_bus.h>
57518da7acSAndrew Turner 
58518da7acSAndrew Turner #include <dev/usb/controller/dwc_otg.h>
59518da7acSAndrew Turner 
60518da7acSAndrew Turner static device_probe_t dwc_otg_probe;
61518da7acSAndrew Turner static device_attach_t dwc_otg_attach;
62518da7acSAndrew Turner static device_attach_t dwc_otg_detach;
63518da7acSAndrew Turner 
64518da7acSAndrew Turner static char *dwc_otg_ids[] = {
65518da7acSAndrew Turner 	"BCM2848",
66518da7acSAndrew Turner 	NULL
67518da7acSAndrew Turner };
68518da7acSAndrew Turner 
69518da7acSAndrew Turner static int
70518da7acSAndrew Turner dwc_otg_probe(device_t dev)
71518da7acSAndrew Turner {
72518da7acSAndrew Turner 	int rv;
73518da7acSAndrew Turner 
74518da7acSAndrew Turner 	if (acpi_disabled("dwc_otg"))
75518da7acSAndrew Turner 		return (ENXIO);
76518da7acSAndrew Turner 
77518da7acSAndrew Turner 	rv = ACPI_ID_PROBE(device_get_parent(dev), dev, dwc_otg_ids, NULL);
78518da7acSAndrew Turner 	if (rv > 0)
79518da7acSAndrew Turner 		return (rv);
80518da7acSAndrew Turner 
81518da7acSAndrew Turner 	device_set_desc(dev, "DWC OTG 2.0 integrated USB controller");
82518da7acSAndrew Turner 
83518da7acSAndrew Turner 	return (BUS_PROBE_DEFAULT);
84518da7acSAndrew Turner }
85518da7acSAndrew Turner 
86518da7acSAndrew Turner static int
87518da7acSAndrew Turner dwc_otg_attach(device_t dev)
88518da7acSAndrew Turner {
89518da7acSAndrew Turner 	struct dwc_otg_softc *sc = device_get_softc(dev);
90518da7acSAndrew Turner 	int err;
91518da7acSAndrew Turner 	int rid;
92518da7acSAndrew Turner 
93518da7acSAndrew Turner 	sc->sc_bus.parent = dev;
94518da7acSAndrew Turner 
95518da7acSAndrew Turner 	/* assume device mode (this is only used for the Raspberry Pi 4's
96518da7acSAndrew Turner 	 * USB-C port, which only works in device mode) */
97518da7acSAndrew Turner 	sc->sc_mode = DWC_MODE_DEVICE;
98518da7acSAndrew Turner 
99518da7acSAndrew Turner 	rid = 0;
100518da7acSAndrew Turner 	sc->sc_io_res =
101518da7acSAndrew Turner 	    bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
102518da7acSAndrew Turner 
103518da7acSAndrew Turner 	if (sc->sc_io_res == NULL)
104518da7acSAndrew Turner 		goto error;
105518da7acSAndrew Turner 
106518da7acSAndrew Turner 	rid = 0;
107518da7acSAndrew Turner 	sc->sc_irq_res =
108518da7acSAndrew Turner 	    bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
109518da7acSAndrew Turner 	if (sc->sc_irq_res == NULL)
110518da7acSAndrew Turner 		goto error;
111518da7acSAndrew Turner 
112518da7acSAndrew Turner 	err = dwc_otg_init(sc);
113518da7acSAndrew Turner 	if (err == 0) {
114518da7acSAndrew Turner 		err = device_probe_and_attach(sc->sc_bus.bdev);
115518da7acSAndrew Turner 	}
116518da7acSAndrew Turner 	if (err)
117518da7acSAndrew Turner 		goto error;
118518da7acSAndrew Turner 
119518da7acSAndrew Turner 	return (0);
120518da7acSAndrew Turner 
121518da7acSAndrew Turner error:
122518da7acSAndrew Turner 	dwc_otg_detach(dev);
123518da7acSAndrew Turner 	return (ENXIO);
124518da7acSAndrew Turner }
125518da7acSAndrew Turner 
126518da7acSAndrew Turner static int
127518da7acSAndrew Turner dwc_otg_detach(device_t dev)
128518da7acSAndrew Turner {
129518da7acSAndrew Turner 	struct dwc_otg_softc *sc = device_get_softc(dev);
130*3ddaf820SJohn Baldwin 	int error;
131518da7acSAndrew Turner 
132518da7acSAndrew Turner 	/* during module unload there are lots of children leftover */
133*3ddaf820SJohn Baldwin 	error = bus_generic_detach(dev);
134*3ddaf820SJohn Baldwin 	if (error != 0)
135*3ddaf820SJohn Baldwin 		return (error);
136518da7acSAndrew Turner 
137518da7acSAndrew Turner 	if (sc->sc_irq_res && sc->sc_intr_hdl) {
138518da7acSAndrew Turner 		/*
139518da7acSAndrew Turner 		 * only call dwc_otg_uninit() after dwc_otg_init()
140518da7acSAndrew Turner 		 */
141518da7acSAndrew Turner 		dwc_otg_uninit(sc);
142518da7acSAndrew Turner 
143518da7acSAndrew Turner 		bus_teardown_intr(dev, sc->sc_irq_res,
144518da7acSAndrew Turner 		    sc->sc_intr_hdl);
145518da7acSAndrew Turner 		sc->sc_intr_hdl = NULL;
146518da7acSAndrew Turner 	}
147518da7acSAndrew Turner 	/* free IRQ channel, if any */
148518da7acSAndrew Turner 	if (sc->sc_irq_res) {
149518da7acSAndrew Turner 		bus_release_resource(dev, SYS_RES_IRQ, 0,
150518da7acSAndrew Turner 		    sc->sc_irq_res);
151518da7acSAndrew Turner 		sc->sc_irq_res = NULL;
152518da7acSAndrew Turner 	}
153518da7acSAndrew Turner 	/* free memory resource, if any */
154518da7acSAndrew Turner 	if (sc->sc_io_res) {
155518da7acSAndrew Turner 		bus_release_resource(dev, SYS_RES_MEMORY, 0,
156518da7acSAndrew Turner 		    sc->sc_io_res);
157518da7acSAndrew Turner 		sc->sc_io_res = NULL;
158518da7acSAndrew Turner 	}
159518da7acSAndrew Turner 	usb_bus_mem_free_all(&sc->sc_bus, NULL);
160518da7acSAndrew Turner 
161518da7acSAndrew Turner 	return (0);
162518da7acSAndrew Turner }
163518da7acSAndrew Turner 
164518da7acSAndrew Turner static device_method_t dwc_otg_methods[] = {
165518da7acSAndrew Turner 	/* Device interface */
166518da7acSAndrew Turner 	DEVMETHOD(device_probe, dwc_otg_probe),
167518da7acSAndrew Turner 	DEVMETHOD(device_attach, dwc_otg_attach),
168518da7acSAndrew Turner 	DEVMETHOD(device_detach, dwc_otg_detach),
169518da7acSAndrew Turner 	DEVMETHOD(device_suspend, bus_generic_suspend),
170518da7acSAndrew Turner 	DEVMETHOD(device_resume, bus_generic_resume),
171518da7acSAndrew Turner 	DEVMETHOD(device_shutdown, bus_generic_shutdown),
172518da7acSAndrew Turner 
173518da7acSAndrew Turner 	DEVMETHOD_END
174518da7acSAndrew Turner };
175518da7acSAndrew Turner 
176518da7acSAndrew Turner static driver_t dwc_otg_driver = {
177518da7acSAndrew Turner 	.name = "dwcotg",
178518da7acSAndrew Turner 	.methods = dwc_otg_methods,
179518da7acSAndrew Turner 	.size = sizeof(struct dwc_otg_softc),
180518da7acSAndrew Turner };
181518da7acSAndrew Turner 
182bc9372d7SJohn Baldwin DRIVER_MODULE(dwcotg, acpi, dwc_otg_driver, 0, 0);
183518da7acSAndrew Turner MODULE_DEPEND(dwcotg, usb, 1, 1, 1);
184