xref: /freebsd/sys/dev/usb/controller/dwc_otg_acpi.c (revision ca48e43ba9ee73a07cdbad8365117793b01273bb)
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 "opt_acpi.h"
29518da7acSAndrew Turner 
30518da7acSAndrew Turner #include <sys/param.h>
31518da7acSAndrew Turner #include <sys/systm.h>
32518da7acSAndrew Turner #include <sys/bus.h>
33518da7acSAndrew Turner #include <sys/condvar.h>
34518da7acSAndrew Turner #include <sys/kernel.h>
35518da7acSAndrew Turner #include <sys/lock.h>
36518da7acSAndrew Turner #include <sys/malloc.h>
37518da7acSAndrew Turner #include <sys/module.h>
38518da7acSAndrew Turner #include <sys/mutex.h>
39518da7acSAndrew Turner #include <sys/rman.h>
40518da7acSAndrew Turner 
41518da7acSAndrew Turner #include <contrib/dev/acpica/include/acpi.h>
42518da7acSAndrew Turner #include <contrib/dev/acpica/include/accommon.h>
43518da7acSAndrew Turner 
44518da7acSAndrew Turner #include <dev/acpica/acpivar.h>
45518da7acSAndrew Turner 
46518da7acSAndrew Turner #include <dev/usb/usb.h>
47518da7acSAndrew Turner #include <dev/usb/usbdi.h>
48518da7acSAndrew Turner 
49518da7acSAndrew Turner #include <dev/usb/usb_core.h>
50518da7acSAndrew Turner #include <dev/usb/usb_busdma.h>
51518da7acSAndrew Turner #include <dev/usb/usb_process.h>
52518da7acSAndrew Turner #include <dev/usb/usb_util.h>
53518da7acSAndrew Turner 
54518da7acSAndrew Turner #include <dev/usb/usb_controller.h>
55518da7acSAndrew Turner #include <dev/usb/usb_bus.h>
56518da7acSAndrew Turner 
57518da7acSAndrew Turner #include <dev/usb/controller/dwc_otg.h>
58518da7acSAndrew Turner 
59518da7acSAndrew Turner static device_probe_t dwc_otg_probe;
60518da7acSAndrew Turner static device_attach_t dwc_otg_attach;
61518da7acSAndrew Turner static device_attach_t dwc_otg_detach;
62518da7acSAndrew Turner 
63518da7acSAndrew Turner static char *dwc_otg_ids[] = {
64518da7acSAndrew Turner 	"BCM2848",
65518da7acSAndrew Turner 	NULL
66518da7acSAndrew Turner };
67518da7acSAndrew Turner 
68518da7acSAndrew Turner static int
dwc_otg_probe(device_t dev)69518da7acSAndrew Turner dwc_otg_probe(device_t dev)
70518da7acSAndrew Turner {
71518da7acSAndrew Turner 	int rv;
72518da7acSAndrew Turner 
73518da7acSAndrew Turner 	if (acpi_disabled("dwc_otg"))
74518da7acSAndrew Turner 		return (ENXIO);
75518da7acSAndrew Turner 
76518da7acSAndrew Turner 	rv = ACPI_ID_PROBE(device_get_parent(dev), dev, dwc_otg_ids, NULL);
77518da7acSAndrew Turner 	if (rv > 0)
78518da7acSAndrew Turner 		return (rv);
79518da7acSAndrew Turner 
80518da7acSAndrew Turner 	device_set_desc(dev, "DWC OTG 2.0 integrated USB controller");
81518da7acSAndrew Turner 
82518da7acSAndrew Turner 	return (BUS_PROBE_DEFAULT);
83518da7acSAndrew Turner }
84518da7acSAndrew Turner 
85518da7acSAndrew Turner static int
dwc_otg_attach(device_t dev)86518da7acSAndrew Turner dwc_otg_attach(device_t dev)
87518da7acSAndrew Turner {
88518da7acSAndrew Turner 	struct dwc_otg_softc *sc = device_get_softc(dev);
89518da7acSAndrew Turner 	int err;
90518da7acSAndrew Turner 	int rid;
91518da7acSAndrew Turner 
92518da7acSAndrew Turner 	sc->sc_bus.parent = dev;
93518da7acSAndrew Turner 
94518da7acSAndrew Turner 	/* assume device mode (this is only used for the Raspberry Pi 4's
95518da7acSAndrew Turner 	 * USB-C port, which only works in device mode) */
96518da7acSAndrew Turner 	sc->sc_mode = DWC_MODE_DEVICE;
97518da7acSAndrew Turner 
98518da7acSAndrew Turner 	rid = 0;
99518da7acSAndrew Turner 	sc->sc_io_res =
100518da7acSAndrew Turner 	    bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
101518da7acSAndrew Turner 
102518da7acSAndrew Turner 	if (sc->sc_io_res == NULL)
103518da7acSAndrew Turner 		goto error;
104518da7acSAndrew Turner 
105518da7acSAndrew Turner 	rid = 0;
106518da7acSAndrew Turner 	sc->sc_irq_res =
107518da7acSAndrew Turner 	    bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
108518da7acSAndrew Turner 	if (sc->sc_irq_res == NULL)
109518da7acSAndrew Turner 		goto error;
110518da7acSAndrew Turner 
111518da7acSAndrew Turner 	err = dwc_otg_init(sc);
112518da7acSAndrew Turner 	if (err == 0) {
113518da7acSAndrew Turner 		err = device_probe_and_attach(sc->sc_bus.bdev);
114518da7acSAndrew Turner 	}
115518da7acSAndrew Turner 	if (err)
116518da7acSAndrew Turner 		goto error;
117518da7acSAndrew Turner 
118518da7acSAndrew Turner 	return (0);
119518da7acSAndrew Turner 
120518da7acSAndrew Turner error:
121518da7acSAndrew Turner 	dwc_otg_detach(dev);
122518da7acSAndrew Turner 	return (ENXIO);
123518da7acSAndrew Turner }
124518da7acSAndrew Turner 
125518da7acSAndrew Turner static int
dwc_otg_detach(device_t dev)126518da7acSAndrew Turner dwc_otg_detach(device_t dev)
127518da7acSAndrew Turner {
128518da7acSAndrew Turner 	struct dwc_otg_softc *sc = device_get_softc(dev);
129*3ddaf820SJohn Baldwin 	int error;
130518da7acSAndrew Turner 
131518da7acSAndrew Turner 	/* during module unload there are lots of children leftover */
132*3ddaf820SJohn Baldwin 	error = bus_generic_detach(dev);
133*3ddaf820SJohn Baldwin 	if (error != 0)
134*3ddaf820SJohn Baldwin 		return (error);
135518da7acSAndrew Turner 
136518da7acSAndrew Turner 	if (sc->sc_irq_res && sc->sc_intr_hdl) {
137518da7acSAndrew Turner 		/*
138518da7acSAndrew Turner 		 * only call dwc_otg_uninit() after dwc_otg_init()
139518da7acSAndrew Turner 		 */
140518da7acSAndrew Turner 		dwc_otg_uninit(sc);
141518da7acSAndrew Turner 
142518da7acSAndrew Turner 		bus_teardown_intr(dev, sc->sc_irq_res,
143518da7acSAndrew Turner 		    sc->sc_intr_hdl);
144518da7acSAndrew Turner 		sc->sc_intr_hdl = NULL;
145518da7acSAndrew Turner 	}
146518da7acSAndrew Turner 	/* free IRQ channel, if any */
147518da7acSAndrew Turner 	if (sc->sc_irq_res) {
148518da7acSAndrew Turner 		bus_release_resource(dev, SYS_RES_IRQ, 0,
149518da7acSAndrew Turner 		    sc->sc_irq_res);
150518da7acSAndrew Turner 		sc->sc_irq_res = NULL;
151518da7acSAndrew Turner 	}
152518da7acSAndrew Turner 	/* free memory resource, if any */
153518da7acSAndrew Turner 	if (sc->sc_io_res) {
154518da7acSAndrew Turner 		bus_release_resource(dev, SYS_RES_MEMORY, 0,
155518da7acSAndrew Turner 		    sc->sc_io_res);
156518da7acSAndrew Turner 		sc->sc_io_res = NULL;
157518da7acSAndrew Turner 	}
158518da7acSAndrew Turner 	usb_bus_mem_free_all(&sc->sc_bus, NULL);
159518da7acSAndrew Turner 
160518da7acSAndrew Turner 	return (0);
161518da7acSAndrew Turner }
162518da7acSAndrew Turner 
163518da7acSAndrew Turner static device_method_t dwc_otg_methods[] = {
164518da7acSAndrew Turner 	/* Device interface */
165518da7acSAndrew Turner 	DEVMETHOD(device_probe, dwc_otg_probe),
166518da7acSAndrew Turner 	DEVMETHOD(device_attach, dwc_otg_attach),
167518da7acSAndrew Turner 	DEVMETHOD(device_detach, dwc_otg_detach),
168518da7acSAndrew Turner 	DEVMETHOD(device_suspend, bus_generic_suspend),
169518da7acSAndrew Turner 	DEVMETHOD(device_resume, bus_generic_resume),
170518da7acSAndrew Turner 	DEVMETHOD(device_shutdown, bus_generic_shutdown),
171518da7acSAndrew Turner 
172518da7acSAndrew Turner 	DEVMETHOD_END
173518da7acSAndrew Turner };
174518da7acSAndrew Turner 
175518da7acSAndrew Turner static driver_t dwc_otg_driver = {
176518da7acSAndrew Turner 	.name = "dwcotg",
177518da7acSAndrew Turner 	.methods = dwc_otg_methods,
178518da7acSAndrew Turner 	.size = sizeof(struct dwc_otg_softc),
179518da7acSAndrew Turner };
180518da7acSAndrew Turner 
181bc9372d7SJohn Baldwin DRIVER_MODULE(dwcotg, acpi, dwc_otg_driver, 0, 0);
182518da7acSAndrew Turner MODULE_DEPEND(dwcotg, usb, 1, 1, 1);
183