musb_otg_atmelarm.c revision 187172
1187767Sluigi/* $FreeBSD: head/sys/dev/usb2/controller/musb2_otg_atmelarm.c 187172 2009-01-13 19:03:01Z thompsa $ */
2187767Sluigi/*-
3187767Sluigi * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
4187767Sluigi *
5187767Sluigi * Redistribution and use in source and binary forms, with or without
6187767Sluigi * modification, are permitted provided that the following conditions
7187767Sluigi * are met:
8187767Sluigi * 1. Redistributions of source code must retain the above copyright
9187767Sluigi *    notice, this list of conditions and the following disclaimer.
10187767Sluigi * 2. Redistributions in binary form must reproduce the above copyright
11187767Sluigi *    notice, this list of conditions and the following disclaimer in the
12187767Sluigi *    documentation and/or other materials provided with the distribution.
13187767Sluigi *
14187767Sluigi * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15187767Sluigi * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16187767Sluigi * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17187767Sluigi * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18187767Sluigi * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19187767Sluigi * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20187767Sluigi * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21187767Sluigi * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22187767Sluigi * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23187767Sluigi * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24187767Sluigi * SUCH DAMAGE.
25187767Sluigi */
26187767Sluigi
27187767Sluigi#include <dev/usb2/include/usb2_mfunc.h>
28187767Sluigi#include <dev/usb2/include/usb2_defs.h>
29187767Sluigi#include <dev/usb2/include/usb2_standard.h>
30187767Sluigi
31187767Sluigi#include <dev/usb2/core/usb2_core.h>
32187767Sluigi#include <dev/usb2/core/usb2_busdma.h>
33187767Sluigi#include <dev/usb2/core/usb2_process.h>
34187767Sluigi#include <dev/usb2/core/usb2_sw_transfer.h>
35187767Sluigi#include <dev/usb2/core/usb2_util.h>
36187767Sluigi
37187767Sluigi#include <dev/usb2/controller/usb2_controller.h>
38204591Sluigi#include <dev/usb2/controller/usb2_bus.h>
39187767Sluigi#include <dev/usb2/controller/musb2_otg.h>
40187767Sluigi
41187767Sluigi#include <sys/rman.h>
42187767Sluigi
43187767Sluigistatic device_probe_t musbotg_probe;
44187767Sluigistatic device_attach_t musbotg_attach;
45187767Sluigistatic device_detach_t musbotg_detach;
46187767Sluigistatic device_shutdown_t musbotg_shutdown;
47187767Sluigi
48187767Sluigistruct musbotg_super_softc {
49346205Sae	struct musbotg_softc sc_otg;	/* must be first */
50346205Sae};
51187767Sluigi
52187767Sluigistatic void
53187767Sluigimusbotg_vbus_interrupt(struct musbotg_super_softc *sc)
54187767Sluigi{
55187767Sluigi	uint8_t vbus_val = 1;		/* fake VBUS on - TODO */
56187767Sluigi
57187767Sluigi	/* just forward it */
58187767Sluigi
59332400Sae	(sc->sc_otg.sc_bus.methods->vbus_interrupt)
60332400Sae	    (&sc->sc_otg.sc_bus, vbus_val);
61332400Sae}
62332400Sae
63332400Saestatic void
64332400Saemusbotg_clocks_on(void *arg)
65187767Sluigi{
66187767Sluigi#if 0
67187767Sluigi	struct musbotg_super_softc *sc = arg;
68187767Sluigi
69187767Sluigi#endif
70187767Sluigi}
71187767Sluigi
72187767Sluigistatic void
73187767Sluigimusbotg_clocks_off(void *arg)
74187767Sluigi{
75187767Sluigi#if 0
76187767Sluigi	struct musbotg_super_softc *sc = arg;
77187767Sluigi
78187767Sluigi#endif
79187767Sluigi}
80270424Smelifaro
81270424Smelifarostatic int
82187769Sluigimusbotg_probe(device_t dev)
83187769Sluigi{
84187769Sluigi	device_set_desc(dev, "MUSB OTG integrated USB controller");
85187769Sluigi	return (0);
86187769Sluigi}
87187769Sluigi
88187769Sluigistatic int
89187769Sluigimusbotg_attach(device_t dev)
90332229Stuexen{
91332229Stuexen	struct musbotg_super_softc *sc = device_get_softc(dev);
92187769Sluigi	int err;
93187769Sluigi	int rid;
94298016Sae
95187769Sluigi	if (sc == NULL) {
96204591Sluigi		return (ENXIO);
97187769Sluigi	}
98204591Sluigi	/* setup MUSB OTG USB controller interface softc */
99204591Sluigi
100187769Sluigi	sc->sc_otg.sc_clocks_on = &musbotg_clocks_on;
101187769Sluigi	sc->sc_otg.sc_clocks_off = &musbotg_clocks_off;
102187769Sluigi	sc->sc_otg.sc_clocks_arg = sc;
103187769Sluigi
104187769Sluigi	/* initialise some bus fields */
105187769Sluigi	sc->sc_otg.sc_bus.parent = dev;
106187769Sluigi	sc->sc_otg.sc_bus.devices = sc->sc_otg.sc_devices;
107187769Sluigi	sc->sc_otg.sc_bus.devices_max = MUSB2_MAX_DEVICES;
108187769Sluigi
109187769Sluigi	/* get all DMA memory */
110187769Sluigi	if (usb2_bus_mem_alloc_all(&sc->sc_otg.sc_bus,
111187769Sluigi	    USB_GET_DMA_TAG(dev), NULL)) {
112190633Spiso		return (ENOMEM);
113223666Sae	}
114223666Sae	rid = 0;
115187769Sluigi	sc->sc_otg.sc_io_res =
116187769Sluigi	    bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
117187769Sluigi
118187769Sluigi	if (!(sc->sc_otg.sc_io_res)) {
119187769Sluigi		err = ENOMEM;
120187769Sluigi		goto error;
121187769Sluigi	}
122187769Sluigi	sc->sc_otg.sc_io_tag = rman_get_bustag(sc->sc_otg.sc_io_res);
123187769Sluigi	sc->sc_otg.sc_io_hdl = rman_get_bushandle(sc->sc_otg.sc_io_res);
124187769Sluigi	sc->sc_otg.sc_io_size = rman_get_size(sc->sc_otg.sc_io_res);
125187769Sluigi
126187769Sluigi	rid = 0;
127337461Sae	sc->sc_otg.sc_irq_res =
128187769Sluigi	    bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
129337461Sae	if (!(sc->sc_otg.sc_irq_res)) {
130187769Sluigi		goto error;
131187769Sluigi	}
132187769Sluigi	sc->sc_otg.sc_bus.bdev = device_add_child(dev, "usbus", -1);
133187769Sluigi	if (!(sc->sc_otg.sc_bus.bdev)) {
134187769Sluigi		goto error;
135187769Sluigi	}
136187769Sluigi	device_set_ivars(sc->sc_otg.sc_bus.bdev, &sc->sc_otg.sc_bus);
137187769Sluigi
138187769Sluigi#if (__FreeBSD_version >= 700031)
139187769Sluigi	err = bus_setup_intr(dev, sc->sc_otg.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
140187769Sluigi	    NULL, (void *)musbotg_interrupt, sc, &sc->sc_otg.sc_intr_hdl);
141187769Sluigi#else
142187769Sluigi	err = bus_setup_intr(dev, sc->sc_otg.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
143205169Sluigi	    (void *)musbotg_interrupt, sc, &sc->sc_otg.sc_intr_hdl);
144187769Sluigi#endif
145187769Sluigi	if (err) {
146187769Sluigi		sc->sc_otg.sc_intr_hdl = NULL;
147187769Sluigi		goto error;
148187769Sluigi	}
149187769Sluigi	err = musbotg_init(&sc->sc_otg);
150187769Sluigi	if (!err) {
151187769Sluigi		err = device_probe_and_attach(sc->sc_otg.sc_bus.bdev);
152187769Sluigi	}
153187769Sluigi	if (err) {
154349573Sae		goto error;
155187769Sluigi	} else {
156187769Sluigi		/* poll VBUS one time */
157187769Sluigi		musbotg_vbus_interrupt(sc);
158187769Sluigi	}
159187769Sluigi	return (0);
160187769Sluigi
161187769Sluigierror:
162187769Sluigi	musbotg_detach(dev);
163187769Sluigi	return (ENXIO);
164187769Sluigi}
165187769Sluigi
166187769Sluigistatic int
167187769Sluigimusbotg_detach(device_t dev)
168187769Sluigi{
169187769Sluigi	struct musbotg_super_softc *sc = device_get_softc(dev);
170187769Sluigi	device_t bdev;
171187769Sluigi	int err;
172187769Sluigi
173187769Sluigi	if (sc->sc_otg.sc_bus.bdev) {
174204591Sluigi		bdev = sc->sc_otg.sc_bus.bdev;
175204591Sluigi		device_detach(bdev);
176187769Sluigi		device_delete_child(dev, bdev);
177187769Sluigi	}
178204591Sluigi	/* during module unload there are lots of children leftover */
179194930Soleg	device_delete_all_children(dev);
180187769Sluigi
181187769Sluigi	if (sc->sc_otg.sc_irq_res && sc->sc_otg.sc_intr_hdl) {
182266941Shiren		/*
183187769Sluigi		 * only call musbotg_uninit() after musbotg_init()
184187769Sluigi		 */
185300779Struckman		musbotg_uninit(&sc->sc_otg);
186300779Struckman
187300779Struckman		err = bus_teardown_intr(dev, sc->sc_otg.sc_irq_res,
188300779Struckman		    sc->sc_otg.sc_intr_hdl);
189300779Struckman		sc->sc_otg.sc_intr_hdl = NULL;
190300779Struckman	}
191300779Struckman	/* free IRQ channel, if any */
192300779Struckman	if (sc->sc_otg.sc_irq_res) {
193300779Struckman		bus_release_resource(dev, SYS_RES_IRQ, 0,
194300779Struckman		    sc->sc_otg.sc_irq_res);
195300779Struckman		sc->sc_otg.sc_irq_res = NULL;
196300779Struckman	}
197300779Struckman	/* free memory resource, if any */
198300779Struckman	if (sc->sc_otg.sc_io_res) {
199300779Struckman		bus_release_resource(dev, SYS_RES_MEMORY, 0,
200300779Struckman		    sc->sc_otg.sc_io_res);
201300779Struckman		sc->sc_otg.sc_io_res = NULL;
202300779Struckman	}
203300779Struckman	usb2_bus_mem_free_all(&sc->sc_otg.sc_bus, NULL);
204300779Struckman
205300779Struckman	return (0);
206300779Struckman}
207300779Struckman
208300779Struckmanstatic int
209300779Struckmanmusbotg_shutdown(device_t dev)
210204591Sluigi{
211187769Sluigi	struct musbotg_super_softc *sc = device_get_softc(dev);
212204591Sluigi	int err;
213204591Sluigi
214204591Sluigi	err = bus_generic_shutdown(dev);
215204591Sluigi	if (err)
216204591Sluigi		return (err);
217187769Sluigi
218187769Sluigi	musbotg_uninit(&sc->sc_otg);
219332210Stuexen
220332210Stuexen	return (0);
221332210Stuexen}
222332210Stuexen
223223080Saestatic device_method_t musbotg_methods[] = {
224332210Stuexen	/* Device interface */
225332210Stuexen	DEVMETHOD(device_probe, musbotg_probe),
226332210Stuexen	DEVMETHOD(device_attach, musbotg_attach),
227187769Sluigi	DEVMETHOD(device_detach, musbotg_detach),
228187769Sluigi	DEVMETHOD(device_shutdown, musbotg_shutdown),
229220804Sglebius
230187769Sluigi	/* Bus interface */
231187769Sluigi	DEVMETHOD(bus_print_child, bus_generic_print_child),
232187769Sluigi
233187769Sluigi	{0, 0}
234187769Sluigi};
235187769Sluigi
236187769Sluigistatic driver_t musbotg_driver = {
237187769Sluigi	"musbotg",
238187769Sluigi	musbotg_methods,
239187769Sluigi	sizeof(struct musbotg_super_softc),
240187769Sluigi};
241187769Sluigi
242187769Sluigistatic devclass_t musbotg_devclass;
243187769Sluigi
244200567SluigiDRIVER_MODULE(musbotg, atmelarm, musbotg_driver, musbotg_devclass, 0, 0);
245215179SluigiMODULE_DEPEND(musbotg, usb2_controller, 1, 1, 1);
246248552SmelifaroMODULE_DEPEND(musbotg, usb2_core, 1, 1, 1);
247272840Smelifaro