atmegadci_atmelarm.c revision 228483
1184610Salfred#include <sys/cdefs.h>
2184610Salfred__FBSDID("$FreeBSD: head/sys/dev/usb/controller/atmegadci_atmelarm.c 228483 2011-12-14 00:28:54Z hselasky $");
3184610Salfred
4184610Salfred/*-
5184610Salfred * Copyright (c) 2009 Hans Petter Selasky. All rights reserved.
6184610Salfred *
7184610Salfred * Redistribution and use in source and binary forms, with or without
8184610Salfred * modification, are permitted provided that the following conditions
9184610Salfred * are met:
10184610Salfred * 1. Redistributions of source code must retain the above copyright
11184610Salfred *    notice, this list of conditions and the following disclaimer.
12184610Salfred * 2. Redistributions in binary form must reproduce the above copyright
13184610Salfred *    notice, this list of conditions and the following disclaimer in the
14184610Salfred *    documentation and/or other materials provided with the distribution.
15184610Salfred *
16184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19184610Salfred * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26184610Salfred * SUCH DAMAGE.
27184610Salfred */
28184610Salfred
29184610Salfred#include <sys/stdint.h>
30184610Salfred#include <sys/stddef.h>
31184610Salfred#include <sys/param.h>
32184610Salfred#include <sys/queue.h>
33184610Salfred#include <sys/types.h>
34184610Salfred#include <sys/systm.h>
35184610Salfred#include <sys/kernel.h>
36184610Salfred#include <sys/bus.h>
37184610Salfred#include <sys/module.h>
38184610Salfred#include <sys/lock.h>
39184610Salfred#include <sys/mutex.h>
40184610Salfred#include <sys/condvar.h>
41184610Salfred#include <sys/sysctl.h>
42184610Salfred#include <sys/sx.h>
43184610Salfred#include <sys/unistd.h>
44184610Salfred#include <sys/callout.h>
45184610Salfred#include <sys/malloc.h>
46184610Salfred#include <sys/priv.h>
47184610Salfred
48184610Salfred#include <dev/usb/usb.h>
49184610Salfred#include <dev/usb/usbdi.h>
50184610Salfred
51184610Salfred#include <dev/usb/usb_core.h>
52184610Salfred#include <dev/usb/usb_busdma.h>
53184610Salfred#include <dev/usb/usb_process.h>
54194677Sthompsa#include <dev/usb/usb_util.h>
55194677Sthompsa
56194677Sthompsa#include <dev/usb/usb_controller.h>
57194677Sthompsa#include <dev/usb/usb_bus.h>
58194677Sthompsa#include <dev/usb/controller/atmegadci.h>
59194677Sthompsa
60194677Sthompsa#include <sys/rman.h>
61194677Sthompsa
62194677Sthompsastatic device_probe_t atmegadci_probe;
63194677Sthompsastatic device_attach_t atmegadci_attach;
64194677Sthompsastatic device_detach_t atmegadci_detach;
65194677Sthompsa
66194677Sthompsastruct atmegadci_super_softc {
67194677Sthompsa	struct atmegadci_softc sc_otg;	/* must be first */
68194677Sthompsa};
69194677Sthompsa
70194677Sthompsastatic void
71194677Sthompsaatmegadci_clocks_on(struct usb_bus *bus)
72194677Sthompsa{
73194677Sthompsa	/* TODO */
74188942Sthompsa}
75194677Sthompsa
76194677Sthompsastatic void
77188942Sthompsaatmegadci_clocks_off(struct usb_bus *bus)
78194677Sthompsa{
79184610Salfred	/* TODO */
80194228Sthompsa}
81188942Sthompsa
82188942Sthompsastatic int
83184610Salfredatmegadci_probe(device_t dev)
84188942Sthompsa{
85184610Salfred	device_set_desc(dev, "ATMEL OTG integrated USB controller");
86184610Salfred	return (0);
87184610Salfred}
88184610Salfred
89184610Salfredstatic int
90184610Salfredatmegadci_attach(device_t dev)
91187259Sthompsa{
92187259Sthompsa	struct atmegadci_super_softc *sc = device_get_softc(dev);
93187259Sthompsa	int err;
94188413Sthompsa	int rid;
95187259Sthompsa
96187259Sthompsa	/* setup MUSB OTG USB controller interface softc */
97184610Salfred	sc->sc_otg.sc_clocks_on = &atmegadci_clocks_on;
98192984Sthompsa	sc->sc_otg.sc_clocks_off = &atmegadci_clocks_off;
99192984Sthompsa
100184610Salfred	/* initialise some bus fields */
101192984Sthompsa	sc->sc_otg.sc_bus.parent = dev;
102192984Sthompsa	sc->sc_otg.sc_bus.devices = sc->sc_otg.sc_devices;
103189265Sthompsa	sc->sc_otg.sc_bus.devices_max = ATMEGA_MAX_DEVICES;
104184610Salfred
105184610Salfred	/* get all DMA memory */
106184610Salfred	if (usb_bus_mem_alloc_all(&sc->sc_otg.sc_bus,
107184610Salfred	    USB_GET_DMA_TAG(dev), NULL)) {
108184610Salfred		return (ENOMEM);
109184610Salfred	}
110184610Salfred	rid = 0;
111184610Salfred	sc->sc_otg.sc_io_res =
112184610Salfred	    bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
113184610Salfred
114184610Salfred	if (!(sc->sc_otg.sc_io_res)) {
115193045Sthompsa		err = ENOMEM;
116193045Sthompsa		goto error;
117184610Salfred	}
118192984Sthompsa	sc->sc_otg.sc_io_tag = rman_get_bustag(sc->sc_otg.sc_io_res);
119192984Sthompsa	sc->sc_otg.sc_io_hdl = rman_get_bushandle(sc->sc_otg.sc_io_res);
120192984Sthompsa
121192984Sthompsa	rid = 0;
122192984Sthompsa	sc->sc_otg.sc_irq_res =
123192984Sthompsa	    bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
124192984Sthompsa	if (!(sc->sc_otg.sc_irq_res)) {
125184610Salfred		goto error;
126192984Sthompsa	}
127184610Salfred	sc->sc_otg.sc_bus.bdev = device_add_child(dev, "usbus", -1);
128187259Sthompsa	if (!(sc->sc_otg.sc_bus.bdev)) {
129184610Salfred		goto error;
130184610Salfred	}
131184610Salfred	device_set_ivars(sc->sc_otg.sc_bus.bdev, &sc->sc_otg.sc_bus);
132190734Sthompsa
133190734Sthompsa	err = bus_setup_intr(dev, sc->sc_otg.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
134190734Sthompsa	    NULL, (driver_intr_t *)atmegadci_interrupt, sc, &sc->sc_otg.sc_intr_hdl);
135184610Salfred	if (err) {
136184610Salfred		sc->sc_otg.sc_intr_hdl = NULL;
137187259Sthompsa		goto error;
138184610Salfred	}
139184610Salfred	err = atmegadci_init(&sc->sc_otg);
140184610Salfred	if (!err) {
141190734Sthompsa		err = device_probe_and_attach(sc->sc_otg.sc_bus.bdev);
142190734Sthompsa	}
143190734Sthompsa	if (err) {
144184610Salfred		goto error;
145184610Salfred	}
146184610Salfred	return (0);
147192984Sthompsa
148194228Sthompsaerror:
149194228Sthompsa	atmegadci_detach(dev);
150194228Sthompsa	return (ENXIO);
151194228Sthompsa}
152194228Sthompsa
153194228Sthompsastatic int
154194228Sthompsaatmegadci_detach(device_t dev)
155184610Salfred{
156184610Salfred	struct atmegadci_super_softc *sc = device_get_softc(dev);
157184610Salfred	device_t bdev;
158184610Salfred	int err;
159184610Salfred
160184610Salfred	if (sc->sc_otg.sc_bus.bdev) {
161184610Salfred		bdev = sc->sc_otg.sc_bus.bdev;
162192984Sthompsa		device_detach(bdev);
163184610Salfred		device_delete_child(dev, bdev);
164184610Salfred	}
165184610Salfred	/* during module unload there are lots of children leftover */
166184610Salfred	device_delete_children(dev);
167184610Salfred
168184610Salfred	if (sc->sc_otg.sc_irq_res && sc->sc_otg.sc_intr_hdl) {
169184610Salfred		/*
170184610Salfred		 * only call atmegadci_uninit() after atmegadci_init()
171184610Salfred		 */
172184610Salfred		atmegadci_uninit(&sc->sc_otg);
173184610Salfred
174184610Salfred		err = bus_teardown_intr(dev, sc->sc_otg.sc_irq_res,
175184610Salfred		    sc->sc_otg.sc_intr_hdl);
176184610Salfred		sc->sc_otg.sc_intr_hdl = NULL;
177184610Salfred	}
178184610Salfred	/* free IRQ channel, if any */
179184610Salfred	if (sc->sc_otg.sc_irq_res) {
180184610Salfred		bus_release_resource(dev, SYS_RES_IRQ, 0,
181184610Salfred		    sc->sc_otg.sc_irq_res);
182184610Salfred		sc->sc_otg.sc_irq_res = NULL;
183184610Salfred	}
184184610Salfred	/* free memory resource, if any */
185184610Salfred	if (sc->sc_otg.sc_io_res) {
186184610Salfred		bus_release_resource(dev, SYS_RES_MEMORY, 0,
187184610Salfred		    sc->sc_otg.sc_io_res);
188184610Salfred		sc->sc_otg.sc_io_res = NULL;
189184610Salfred	}
190184610Salfred	usb_bus_mem_free_all(&sc->sc_otg.sc_bus, NULL);
191184610Salfred
192184610Salfred	return (0);
193184610Salfred}
194184610Salfred
195184610Salfredstatic device_method_t atmegadci_methods[] = {
196184610Salfred	/* Device interface */
197184610Salfred	DEVMETHOD(device_probe, atmegadci_probe),
198184610Salfred	DEVMETHOD(device_attach, atmegadci_attach),
199184610Salfred	DEVMETHOD(device_detach, atmegadci_detach),
200184610Salfred	DEVMETHOD(device_suspend, bus_generic_suspend),
201184610Salfred	DEVMETHOD(device_resume, bus_generic_resume),
202184610Salfred	DEVMETHOD(device_shutdown, bus_generic_shutdown),
203184610Salfred
204184610Salfred	DEVMETHOD_END
205184610Salfred};
206184610Salfred
207184610Salfredstatic driver_t atmegadci_driver = {
208184610Salfred	.name = "atmegadci",
209184610Salfred	.methods = atmegadci_methods,
210184610Salfred	.size = sizeof(struct atmegadci_super_softc),
211184610Salfred};
212184610Salfred
213184610Salfredstatic devclass_t atmegadci_devclass;
214184610Salfred
215184610SalfredDRIVER_MODULE(atmegadci, atmelarm, atmegadci_driver, atmegadci_devclass, 0, 0);
216184610SalfredMODULE_DEPEND(atmegadci, usb, 1, 1, 1);
217184610Salfred