atmegadci_atmelarm.c revision 194677
1187160Sthompsa#include <sys/cdefs.h>
2187160Sthompsa__FBSDID("$FreeBSD: head/sys/dev/usb/controller/atmegadci_atmelarm.c 194677 2009-06-23 02:19:59Z thompsa $");
3187160Sthompsa
4187160Sthompsa/*-
5187160Sthompsa * Copyright (c) 2009 Hans Petter Selasky. All rights reserved.
6187160Sthompsa *
7187160Sthompsa * Redistribution and use in source and binary forms, with or without
8187160Sthompsa * modification, are permitted provided that the following conditions
9187160Sthompsa * are met:
10187160Sthompsa * 1. Redistributions of source code must retain the above copyright
11187160Sthompsa *    notice, this list of conditions and the following disclaimer.
12187160Sthompsa * 2. Redistributions in binary form must reproduce the above copyright
13187160Sthompsa *    notice, this list of conditions and the following disclaimer in the
14187160Sthompsa *    documentation and/or other materials provided with the distribution.
15187160Sthompsa *
16187160Sthompsa * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17187160Sthompsa * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18187160Sthompsa * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19187160Sthompsa * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20187160Sthompsa * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21187160Sthompsa * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22187160Sthompsa * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23187160Sthompsa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24187160Sthompsa * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25187160Sthompsa * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26187160Sthompsa * SUCH DAMAGE.
27187160Sthompsa */
28189677Sthompsa
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/linker_set.h>
38194677Sthompsa#include <sys/module.h>
39194677Sthompsa#include <sys/lock.h>
40194677Sthompsa#include <sys/mutex.h>
41194677Sthompsa#include <sys/condvar.h>
42194677Sthompsa#include <sys/sysctl.h>
43194677Sthompsa#include <sys/sx.h>
44194677Sthompsa#include <sys/unistd.h>
45194677Sthompsa#include <sys/callout.h>
46194677Sthompsa#include <sys/malloc.h>
47194677Sthompsa#include <sys/priv.h>
48194677Sthompsa
49189677Sthompsa#include <dev/usb/usb.h>
50194677Sthompsa#include <dev/usb/usbdi.h>
51189677Sthompsa
52189677Sthompsa#include <dev/usb/usb_core.h>
53189677Sthompsa#include <dev/usb/usb_busdma.h>
54189677Sthompsa#include <dev/usb/usb_process.h>
55189677Sthompsa#include <dev/usb/usb_util.h>
56189677Sthompsa
57189677Sthompsa#include <dev/usb/usb_controller.h>
58189677Sthompsa#include <dev/usb/usb_bus.h>
59189677Sthompsa#include <dev/usb/controller/atmegadci.h>
60189677Sthompsa
61189677Sthompsa#include <sys/rman.h>
62189677Sthompsa
63189677Sthompsastatic device_probe_t atmegadci_probe;
64189677Sthompsastatic device_attach_t atmegadci_attach;
65189677Sthompsastatic device_detach_t atmegadci_detach;
66189677Sthompsastatic device_shutdown_t atmegadci_shutdown;
67189677Sthompsa
68189677Sthompsastruct atmegadci_super_softc {
69189677Sthompsa	struct atmegadci_softc sc_otg;	/* must be first */
70189677Sthompsa};
71189677Sthompsa
72189677Sthompsastatic void
73192984Sthompsaatmegadci_clocks_on(struct usb_bus *bus)
74189677Sthompsa{
75189677Sthompsa	/* TODO */
76189677Sthompsa}
77189677Sthompsa
78189677Sthompsastatic void
79192984Sthompsaatmegadci_clocks_off(struct usb_bus *bus)
80189677Sthompsa{
81189677Sthompsa	/* TODO */
82189677Sthompsa}
83189677Sthompsa
84189677Sthompsastatic int
85189677Sthompsaatmegadci_probe(device_t dev)
86189677Sthompsa{
87189677Sthompsa	device_set_desc(dev, "ATMEL OTG integrated USB controller");
88189677Sthompsa	return (0);
89189677Sthompsa}
90189677Sthompsa
91189677Sthompsastatic int
92189677Sthompsaatmegadci_attach(device_t dev)
93189677Sthompsa{
94189677Sthompsa	struct atmegadci_super_softc *sc = device_get_softc(dev);
95189677Sthompsa	int err;
96189677Sthompsa	int rid;
97189677Sthompsa
98189677Sthompsa	/* setup MUSB OTG USB controller interface softc */
99189677Sthompsa	sc->sc_otg.sc_clocks_on = &atmegadci_clocks_on;
100189677Sthompsa	sc->sc_otg.sc_clocks_off = &atmegadci_clocks_off;
101189677Sthompsa
102189677Sthompsa	/* initialise some bus fields */
103189677Sthompsa	sc->sc_otg.sc_bus.parent = dev;
104189677Sthompsa	sc->sc_otg.sc_bus.devices = sc->sc_otg.sc_devices;
105189677Sthompsa	sc->sc_otg.sc_bus.devices_max = ATMEGA_MAX_DEVICES;
106189677Sthompsa
107189677Sthompsa	/* get all DMA memory */
108194228Sthompsa	if (usb_bus_mem_alloc_all(&sc->sc_otg.sc_bus,
109189677Sthompsa	    USB_GET_DMA_TAG(dev), NULL)) {
110189677Sthompsa		return (ENOMEM);
111189677Sthompsa	}
112189677Sthompsa	rid = 0;
113189677Sthompsa	sc->sc_otg.sc_io_res =
114189677Sthompsa	    bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
115189677Sthompsa
116189677Sthompsa	if (!(sc->sc_otg.sc_io_res)) {
117189677Sthompsa		err = ENOMEM;
118189677Sthompsa		goto error;
119189677Sthompsa	}
120189677Sthompsa	sc->sc_otg.sc_io_tag = rman_get_bustag(sc->sc_otg.sc_io_res);
121189677Sthompsa	sc->sc_otg.sc_io_hdl = rman_get_bushandle(sc->sc_otg.sc_io_res);
122189677Sthompsa
123189677Sthompsa	rid = 0;
124189677Sthompsa	sc->sc_otg.sc_irq_res =
125189677Sthompsa	    bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
126189677Sthompsa	if (!(sc->sc_otg.sc_irq_res)) {
127189677Sthompsa		goto error;
128189677Sthompsa	}
129189677Sthompsa	sc->sc_otg.sc_bus.bdev = device_add_child(dev, "usbus", -1);
130189677Sthompsa	if (!(sc->sc_otg.sc_bus.bdev)) {
131189677Sthompsa		goto error;
132189677Sthompsa	}
133189677Sthompsa	device_set_ivars(sc->sc_otg.sc_bus.bdev, &sc->sc_otg.sc_bus);
134189677Sthompsa
135189677Sthompsa	err = bus_setup_intr(dev, sc->sc_otg.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
136190183Sthompsa	    NULL, (driver_intr_t *)atmegadci_interrupt, sc, &sc->sc_otg.sc_intr_hdl);
137189677Sthompsa	if (err) {
138189677Sthompsa		sc->sc_otg.sc_intr_hdl = NULL;
139189677Sthompsa		goto error;
140189677Sthompsa	}
141189677Sthompsa	err = atmegadci_init(&sc->sc_otg);
142189677Sthompsa	if (!err) {
143189677Sthompsa		err = device_probe_and_attach(sc->sc_otg.sc_bus.bdev);
144189677Sthompsa	}
145189677Sthompsa	if (err) {
146189677Sthompsa		goto error;
147189677Sthompsa	}
148189677Sthompsa	return (0);
149189677Sthompsa
150189677Sthompsaerror:
151189677Sthompsa	atmegadci_detach(dev);
152189677Sthompsa	return (ENXIO);
153189677Sthompsa}
154189677Sthompsa
155189677Sthompsastatic int
156189677Sthompsaatmegadci_detach(device_t dev)
157189677Sthompsa{
158189677Sthompsa	struct atmegadci_super_softc *sc = device_get_softc(dev);
159189677Sthompsa	device_t bdev;
160189677Sthompsa	int err;
161189677Sthompsa
162189677Sthompsa	if (sc->sc_otg.sc_bus.bdev) {
163189677Sthompsa		bdev = sc->sc_otg.sc_bus.bdev;
164189677Sthompsa		device_detach(bdev);
165189677Sthompsa		device_delete_child(dev, bdev);
166189677Sthompsa	}
167189677Sthompsa	/* during module unload there are lots of children leftover */
168189677Sthompsa	device_delete_all_children(dev);
169189677Sthompsa
170189677Sthompsa	if (sc->sc_otg.sc_irq_res && sc->sc_otg.sc_intr_hdl) {
171189677Sthompsa		/*
172189677Sthompsa		 * only call atmegadci_uninit() after atmegadci_init()
173189677Sthompsa		 */
174189677Sthompsa		atmegadci_uninit(&sc->sc_otg);
175189677Sthompsa
176189677Sthompsa		err = bus_teardown_intr(dev, sc->sc_otg.sc_irq_res,
177189677Sthompsa		    sc->sc_otg.sc_intr_hdl);
178189677Sthompsa		sc->sc_otg.sc_intr_hdl = NULL;
179189677Sthompsa	}
180189677Sthompsa	/* free IRQ channel, if any */
181189677Sthompsa	if (sc->sc_otg.sc_irq_res) {
182189677Sthompsa		bus_release_resource(dev, SYS_RES_IRQ, 0,
183189677Sthompsa		    sc->sc_otg.sc_irq_res);
184189677Sthompsa		sc->sc_otg.sc_irq_res = NULL;
185189677Sthompsa	}
186189677Sthompsa	/* free memory resource, if any */
187189677Sthompsa	if (sc->sc_otg.sc_io_res) {
188189677Sthompsa		bus_release_resource(dev, SYS_RES_MEMORY, 0,
189189677Sthompsa		    sc->sc_otg.sc_io_res);
190189677Sthompsa		sc->sc_otg.sc_io_res = NULL;
191189677Sthompsa	}
192194228Sthompsa	usb_bus_mem_free_all(&sc->sc_otg.sc_bus, NULL);
193189677Sthompsa
194189677Sthompsa	return (0);
195189677Sthompsa}
196189677Sthompsa
197189677Sthompsastatic int
198189677Sthompsaatmegadci_shutdown(device_t dev)
199189677Sthompsa{
200189677Sthompsa	struct atmegadci_super_softc *sc = device_get_softc(dev);
201189677Sthompsa	int err;
202189677Sthompsa
203189677Sthompsa	err = bus_generic_shutdown(dev);
204189677Sthompsa	if (err)
205189677Sthompsa		return (err);
206189677Sthompsa
207189677Sthompsa	atmegadci_uninit(&sc->sc_otg);
208189677Sthompsa
209189677Sthompsa	return (0);
210189677Sthompsa}
211189677Sthompsa
212189677Sthompsastatic device_method_t atmegadci_methods[] = {
213189677Sthompsa	/* Device interface */
214189677Sthompsa	DEVMETHOD(device_probe, atmegadci_probe),
215189677Sthompsa	DEVMETHOD(device_attach, atmegadci_attach),
216189677Sthompsa	DEVMETHOD(device_detach, atmegadci_detach),
217189677Sthompsa	DEVMETHOD(device_shutdown, atmegadci_shutdown),
218189677Sthompsa
219189677Sthompsa	/* Bus interface */
220189677Sthompsa	DEVMETHOD(bus_print_child, bus_generic_print_child),
221189677Sthompsa
222189677Sthompsa	{0, 0}
223189677Sthompsa};
224189677Sthompsa
225189677Sthompsastatic driver_t atmegadci_driver = {
226189677Sthompsa	"atmegadci",
227189677Sthompsa	atmegadci_methods,
228189677Sthompsa	sizeof(struct atmegadci_super_softc),
229189677Sthompsa};
230189677Sthompsa
231189677Sthompsastatic devclass_t atmegadci_devclass;
232189677Sthompsa
233189677SthompsaDRIVER_MODULE(atmegadci, atmelarm, atmegadci_driver, atmegadci_devclass, 0, 0);
234189677SthompsaMODULE_DEPEND(atmegadci, usb, 1, 1, 1);
235