1184610Salfred/*-
2184610Salfred * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
3184610Salfred *
4184610Salfred * Redistribution and use in source and binary forms, with or without
5184610Salfred * modification, are permitted provided that the following conditions
6184610Salfred * are met:
7184610Salfred * 1. Redistributions of source code must retain the above copyright
8184610Salfred *    notice, this list of conditions and the following disclaimer.
9184610Salfred * 2. Redistributions in binary form must reproduce the above copyright
10184610Salfred *    notice, this list of conditions and the following disclaimer in the
11184610Salfred *    documentation and/or other materials provided with the distribution.
12184610Salfred *
13184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16184610Salfred * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23184610Salfred * SUCH DAMAGE.
24184610Salfred */
25184610Salfred
26227843Smarius#include <sys/cdefs.h>
27227843Smarius__FBSDID("$FreeBSD$");
28227843Smarius
29194677Sthompsa#include <sys/stdint.h>
30194677Sthompsa#include <sys/stddef.h>
31194677Sthompsa#include <sys/param.h>
32194677Sthompsa#include <sys/queue.h>
33194677Sthompsa#include <sys/types.h>
34194677Sthompsa#include <sys/systm.h>
35194677Sthompsa#include <sys/kernel.h>
36194677Sthompsa#include <sys/bus.h>
37194677Sthompsa#include <sys/module.h>
38194677Sthompsa#include <sys/lock.h>
39194677Sthompsa#include <sys/mutex.h>
40194677Sthompsa#include <sys/condvar.h>
41194677Sthompsa#include <sys/sysctl.h>
42194677Sthompsa#include <sys/sx.h>
43194677Sthompsa#include <sys/unistd.h>
44194677Sthompsa#include <sys/callout.h>
45194677Sthompsa#include <sys/malloc.h>
46194677Sthompsa#include <sys/priv.h>
47194677Sthompsa
48188942Sthompsa#include <dev/usb/usb.h>
49194677Sthompsa#include <dev/usb/usbdi.h>
50184610Salfred
51188942Sthompsa#include <dev/usb/usb_core.h>
52188942Sthompsa#include <dev/usb/usb_busdma.h>
53188942Sthompsa#include <dev/usb/usb_process.h>
54188942Sthompsa#include <dev/usb/usb_util.h>
55184610Salfred
56188942Sthompsa#include <dev/usb/usb_controller.h>
57188942Sthompsa#include <dev/usb/usb_bus.h>
58189598Sthompsa#include <dev/usb/controller/musb_otg.h>
59184610Salfred
60184610Salfred#include <sys/rman.h>
61184610Salfred
62184610Salfredstatic device_probe_t musbotg_probe;
63184610Salfredstatic device_attach_t musbotg_attach;
64184610Salfredstatic device_detach_t musbotg_detach;
65184610Salfred
66184610Salfredstruct musbotg_super_softc {
67184610Salfred	struct musbotg_softc sc_otg;	/* must be first */
68184610Salfred};
69184610Salfred
70184610Salfredstatic void
71187175Sthompsamusbotg_vbus_poll(struct musbotg_super_softc *sc)
72184610Salfred{
73184610Salfred	uint8_t vbus_val = 1;		/* fake VBUS on - TODO */
74184610Salfred
75184610Salfred	/* just forward it */
76187175Sthompsa	musbotg_vbus_interrupt(&sc->sc_otg, vbus_val);
77184610Salfred}
78184610Salfred
79184610Salfredstatic void
80184610Salfredmusbotg_clocks_on(void *arg)
81184610Salfred{
82184610Salfred#if 0
83184610Salfred	struct musbotg_super_softc *sc = arg;
84184610Salfred
85184610Salfred#endif
86184610Salfred}
87184610Salfred
88184610Salfredstatic void
89184610Salfredmusbotg_clocks_off(void *arg)
90184610Salfred{
91184610Salfred#if 0
92184610Salfred	struct musbotg_super_softc *sc = arg;
93184610Salfred
94184610Salfred#endif
95184610Salfred}
96184610Salfred
97252912Sgonzostatic void
98252912Sgonzomusbotg_wrapper_interrupt(void *arg)
99252912Sgonzo{
100252912Sgonzo
101252912Sgonzo	/*
102252912Sgonzo	 * Nothing to do.
103252912Sgonzo	 * Main driver takes care about everything
104252912Sgonzo	 */
105252912Sgonzo	musbotg_interrupt(arg, 0, 0, 0);
106252912Sgonzo}
107252912Sgonzo
108252912Sgonzostatic void
109252912Sgonzomusbotg_ep_int_set(struct musbotg_softc *sc, int ep, int on)
110252912Sgonzo{
111252912Sgonzo	/*
112252912Sgonzo	 * Nothing to do.
113252912Sgonzo	 * Main driver takes care about everything
114252912Sgonzo	 */
115252912Sgonzo}
116252912Sgonzo
117184610Salfredstatic int
118184610Salfredmusbotg_probe(device_t dev)
119184610Salfred{
120184610Salfred	device_set_desc(dev, "MUSB OTG integrated USB controller");
121184610Salfred	return (0);
122184610Salfred}
123184610Salfred
124184610Salfredstatic int
125184610Salfredmusbotg_attach(device_t dev)
126184610Salfred{
127184610Salfred	struct musbotg_super_softc *sc = device_get_softc(dev);
128184610Salfred	int err;
129184610Salfred	int rid;
130184610Salfred
131184610Salfred	/* setup MUSB OTG USB controller interface softc */
132184610Salfred	sc->sc_otg.sc_clocks_on = &musbotg_clocks_on;
133184610Salfred	sc->sc_otg.sc_clocks_off = &musbotg_clocks_off;
134184610Salfred	sc->sc_otg.sc_clocks_arg = sc;
135184610Salfred
136187170Sthompsa	/* initialise some bus fields */
137187170Sthompsa	sc->sc_otg.sc_bus.parent = dev;
138187170Sthompsa	sc->sc_otg.sc_bus.devices = sc->sc_otg.sc_devices;
139187170Sthompsa	sc->sc_otg.sc_bus.devices_max = MUSB2_MAX_DEVICES;
140187170Sthompsa
141184610Salfred	/* get all DMA memory */
142194228Sthompsa	if (usb_bus_mem_alloc_all(&sc->sc_otg.sc_bus,
143184610Salfred	    USB_GET_DMA_TAG(dev), NULL)) {
144184610Salfred		return (ENOMEM);
145184610Salfred	}
146184610Salfred	rid = 0;
147184610Salfred	sc->sc_otg.sc_io_res =
148184610Salfred	    bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
149184610Salfred
150184610Salfred	if (!(sc->sc_otg.sc_io_res)) {
151184610Salfred		err = ENOMEM;
152184610Salfred		goto error;
153184610Salfred	}
154184610Salfred	sc->sc_otg.sc_io_tag = rman_get_bustag(sc->sc_otg.sc_io_res);
155184610Salfred	sc->sc_otg.sc_io_hdl = rman_get_bushandle(sc->sc_otg.sc_io_res);
156184610Salfred	sc->sc_otg.sc_io_size = rman_get_size(sc->sc_otg.sc_io_res);
157184610Salfred
158184610Salfred	rid = 0;
159184610Salfred	sc->sc_otg.sc_irq_res =
160184610Salfred	    bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
161184610Salfred	if (!(sc->sc_otg.sc_irq_res)) {
162184610Salfred		goto error;
163184610Salfred	}
164184610Salfred	sc->sc_otg.sc_bus.bdev = device_add_child(dev, "usbus", -1);
165184610Salfred	if (!(sc->sc_otg.sc_bus.bdev)) {
166184610Salfred		goto error;
167184610Salfred	}
168184610Salfred	device_set_ivars(sc->sc_otg.sc_bus.bdev, &sc->sc_otg.sc_bus);
169184610Salfred
170252912Sgonzo	sc->sc_otg.sc_id = 0;
171252912Sgonzo	sc->sc_otg.sc_platform_data = sc;
172252912Sgonzo	sc->sc_otg.sc_mode = MUSB2_DEVICE_MODE;
173252912Sgonzo
174184610Salfred#if (__FreeBSD_version >= 700031)
175184610Salfred	err = bus_setup_intr(dev, sc->sc_otg.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
176252912Sgonzo	    NULL, (driver_intr_t *)musbotg_wrapper_interrupt, sc, &sc->sc_otg.sc_intr_hdl);
177184610Salfred#else
178184610Salfred	err = bus_setup_intr(dev, sc->sc_otg.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
179252912Sgonzo	    (driver_intr_t *)musbotg_wrapper_interrupt, sc, &sc->sc_otg.sc_intr_hdl);
180184610Salfred#endif
181184610Salfred	if (err) {
182184610Salfred		sc->sc_otg.sc_intr_hdl = NULL;
183184610Salfred		goto error;
184184610Salfred	}
185184610Salfred	err = musbotg_init(&sc->sc_otg);
186184610Salfred	if (!err) {
187184610Salfred		err = device_probe_and_attach(sc->sc_otg.sc_bus.bdev);
188184610Salfred	}
189184610Salfred	if (err) {
190184610Salfred		goto error;
191184610Salfred	} else {
192184610Salfred		/* poll VBUS one time */
193187175Sthompsa		musbotg_vbus_poll(sc);
194184610Salfred	}
195184610Salfred	return (0);
196184610Salfred
197184610Salfrederror:
198184610Salfred	musbotg_detach(dev);
199184610Salfred	return (ENXIO);
200184610Salfred}
201184610Salfred
202184610Salfredstatic int
203184610Salfredmusbotg_detach(device_t dev)
204184610Salfred{
205184610Salfred	struct musbotg_super_softc *sc = device_get_softc(dev);
206184610Salfred	device_t bdev;
207184610Salfred	int err;
208184610Salfred
209184610Salfred	if (sc->sc_otg.sc_bus.bdev) {
210184610Salfred		bdev = sc->sc_otg.sc_bus.bdev;
211184610Salfred		device_detach(bdev);
212184610Salfred		device_delete_child(dev, bdev);
213184610Salfred	}
214184610Salfred	/* during module unload there are lots of children leftover */
215227849Shselasky	device_delete_children(dev);
216184610Salfred
217184610Salfred	if (sc->sc_otg.sc_irq_res && sc->sc_otg.sc_intr_hdl) {
218184610Salfred		/*
219184610Salfred		 * only call musbotg_uninit() after musbotg_init()
220184610Salfred		 */
221184610Salfred		musbotg_uninit(&sc->sc_otg);
222184610Salfred
223184610Salfred		err = bus_teardown_intr(dev, sc->sc_otg.sc_irq_res,
224184610Salfred		    sc->sc_otg.sc_intr_hdl);
225184610Salfred		sc->sc_otg.sc_intr_hdl = NULL;
226184610Salfred	}
227184610Salfred	/* free IRQ channel, if any */
228184610Salfred	if (sc->sc_otg.sc_irq_res) {
229184610Salfred		bus_release_resource(dev, SYS_RES_IRQ, 0,
230184610Salfred		    sc->sc_otg.sc_irq_res);
231184610Salfred		sc->sc_otg.sc_irq_res = NULL;
232184610Salfred	}
233184610Salfred	/* free memory resource, if any */
234184610Salfred	if (sc->sc_otg.sc_io_res) {
235184610Salfred		bus_release_resource(dev, SYS_RES_MEMORY, 0,
236184610Salfred		    sc->sc_otg.sc_io_res);
237184610Salfred		sc->sc_otg.sc_io_res = NULL;
238184610Salfred	}
239194228Sthompsa	usb_bus_mem_free_all(&sc->sc_otg.sc_bus, NULL);
240184610Salfred
241184610Salfred	return (0);
242184610Salfred}
243184610Salfred
244184610Salfredstatic device_method_t musbotg_methods[] = {
245184610Salfred	/* Device interface */
246184610Salfred	DEVMETHOD(device_probe, musbotg_probe),
247184610Salfred	DEVMETHOD(device_attach, musbotg_attach),
248184610Salfred	DEVMETHOD(device_detach, musbotg_detach),
249228483Shselasky	DEVMETHOD(device_suspend, bus_generic_suspend),
250228483Shselasky	DEVMETHOD(device_resume, bus_generic_resume),
251228483Shselasky	DEVMETHOD(device_shutdown, bus_generic_shutdown),
252184610Salfred
253227843Smarius	DEVMETHOD_END
254184610Salfred};
255184610Salfred
256184610Salfredstatic driver_t musbotg_driver = {
257228483Shselasky	.name = "musbotg",
258228483Shselasky	.methods = musbotg_methods,
259228483Shselasky	.size = sizeof(struct musbotg_super_softc),
260184610Salfred};
261184610Salfred
262184610Salfredstatic devclass_t musbotg_devclass;
263184610Salfred
264184610SalfredDRIVER_MODULE(musbotg, atmelarm, musbotg_driver, musbotg_devclass, 0, 0);
265188942SthompsaMODULE_DEPEND(musbotg, usb, 1, 1, 1);
266