1187160Sthompsa#include <sys/cdefs.h>
2187160Sthompsa__FBSDID("$FreeBSD: releng/11.0/sys/dev/usb/controller/atmegadci_atmelarm.c 276717 2015-01-05 20:22:18Z hselasky $");
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/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
48189677Sthompsa#include <dev/usb/usb.h>
49194677Sthompsa#include <dev/usb/usbdi.h>
50189677Sthompsa
51189677Sthompsa#include <dev/usb/usb_core.h>
52189677Sthompsa#include <dev/usb/usb_busdma.h>
53189677Sthompsa#include <dev/usb/usb_process.h>
54189677Sthompsa#include <dev/usb/usb_util.h>
55189677Sthompsa
56189677Sthompsa#include <dev/usb/usb_controller.h>
57189677Sthompsa#include <dev/usb/usb_bus.h>
58189677Sthompsa#include <dev/usb/controller/atmegadci.h>
59189677Sthompsa
60189677Sthompsa#include <sys/rman.h>
61189677Sthompsa
62189677Sthompsastatic device_probe_t atmegadci_probe;
63189677Sthompsastatic device_attach_t atmegadci_attach;
64189677Sthompsastatic device_detach_t atmegadci_detach;
65189677Sthompsa
66189677Sthompsastruct atmegadci_super_softc {
67189677Sthompsa	struct atmegadci_softc sc_otg;	/* must be first */
68189677Sthompsa};
69189677Sthompsa
70189677Sthompsastatic void
71192984Sthompsaatmegadci_clocks_on(struct usb_bus *bus)
72189677Sthompsa{
73189677Sthompsa	/* TODO */
74189677Sthompsa}
75189677Sthompsa
76189677Sthompsastatic void
77192984Sthompsaatmegadci_clocks_off(struct usb_bus *bus)
78189677Sthompsa{
79189677Sthompsa	/* TODO */
80189677Sthompsa}
81189677Sthompsa
82189677Sthompsastatic int
83189677Sthompsaatmegadci_probe(device_t dev)
84189677Sthompsa{
85189677Sthompsa	device_set_desc(dev, "ATMEL OTG integrated USB controller");
86189677Sthompsa	return (0);
87189677Sthompsa}
88189677Sthompsa
89189677Sthompsastatic int
90189677Sthompsaatmegadci_attach(device_t dev)
91189677Sthompsa{
92189677Sthompsa	struct atmegadci_super_softc *sc = device_get_softc(dev);
93189677Sthompsa	int err;
94189677Sthompsa	int rid;
95189677Sthompsa
96189677Sthompsa	/* setup MUSB OTG USB controller interface softc */
97189677Sthompsa	sc->sc_otg.sc_clocks_on = &atmegadci_clocks_on;
98189677Sthompsa	sc->sc_otg.sc_clocks_off = &atmegadci_clocks_off;
99189677Sthompsa
100189677Sthompsa	/* initialise some bus fields */
101189677Sthompsa	sc->sc_otg.sc_bus.parent = dev;
102189677Sthompsa	sc->sc_otg.sc_bus.devices = sc->sc_otg.sc_devices;
103189677Sthompsa	sc->sc_otg.sc_bus.devices_max = ATMEGA_MAX_DEVICES;
104276717Shselasky	sc->sc_otg.sc_bus.dma_bits = 32;
105189677Sthompsa
106189677Sthompsa	/* get all DMA memory */
107194228Sthompsa	if (usb_bus_mem_alloc_all(&sc->sc_otg.sc_bus,
108189677Sthompsa	    USB_GET_DMA_TAG(dev), NULL)) {
109189677Sthompsa		return (ENOMEM);
110189677Sthompsa	}
111189677Sthompsa	rid = 0;
112189677Sthompsa	sc->sc_otg.sc_io_res =
113189677Sthompsa	    bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
114189677Sthompsa
115189677Sthompsa	if (!(sc->sc_otg.sc_io_res)) {
116189677Sthompsa		err = ENOMEM;
117189677Sthompsa		goto error;
118189677Sthompsa	}
119189677Sthompsa	sc->sc_otg.sc_io_tag = rman_get_bustag(sc->sc_otg.sc_io_res);
120189677Sthompsa	sc->sc_otg.sc_io_hdl = rman_get_bushandle(sc->sc_otg.sc_io_res);
121189677Sthompsa
122189677Sthompsa	rid = 0;
123189677Sthompsa	sc->sc_otg.sc_irq_res =
124189677Sthompsa	    bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
125189677Sthompsa	if (!(sc->sc_otg.sc_irq_res)) {
126189677Sthompsa		goto error;
127189677Sthompsa	}
128189677Sthompsa	sc->sc_otg.sc_bus.bdev = device_add_child(dev, "usbus", -1);
129189677Sthompsa	if (!(sc->sc_otg.sc_bus.bdev)) {
130189677Sthompsa		goto error;
131189677Sthompsa	}
132189677Sthompsa	device_set_ivars(sc->sc_otg.sc_bus.bdev, &sc->sc_otg.sc_bus);
133189677Sthompsa
134189677Sthompsa	err = bus_setup_intr(dev, sc->sc_otg.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
135190183Sthompsa	    NULL, (driver_intr_t *)atmegadci_interrupt, sc, &sc->sc_otg.sc_intr_hdl);
136189677Sthompsa	if (err) {
137189677Sthompsa		sc->sc_otg.sc_intr_hdl = NULL;
138189677Sthompsa		goto error;
139189677Sthompsa	}
140189677Sthompsa	err = atmegadci_init(&sc->sc_otg);
141189677Sthompsa	if (!err) {
142189677Sthompsa		err = device_probe_and_attach(sc->sc_otg.sc_bus.bdev);
143189677Sthompsa	}
144189677Sthompsa	if (err) {
145189677Sthompsa		goto error;
146189677Sthompsa	}
147189677Sthompsa	return (0);
148189677Sthompsa
149189677Sthompsaerror:
150189677Sthompsa	atmegadci_detach(dev);
151189677Sthompsa	return (ENXIO);
152189677Sthompsa}
153189677Sthompsa
154189677Sthompsastatic int
155189677Sthompsaatmegadci_detach(device_t dev)
156189677Sthompsa{
157189677Sthompsa	struct atmegadci_super_softc *sc = device_get_softc(dev);
158189677Sthompsa	device_t bdev;
159189677Sthompsa	int err;
160189677Sthompsa
161189677Sthompsa	if (sc->sc_otg.sc_bus.bdev) {
162189677Sthompsa		bdev = sc->sc_otg.sc_bus.bdev;
163189677Sthompsa		device_detach(bdev);
164189677Sthompsa		device_delete_child(dev, bdev);
165189677Sthompsa	}
166189677Sthompsa	/* during module unload there are lots of children leftover */
167227849Shselasky	device_delete_children(dev);
168189677Sthompsa
169189677Sthompsa	if (sc->sc_otg.sc_irq_res && sc->sc_otg.sc_intr_hdl) {
170189677Sthompsa		/*
171189677Sthompsa		 * only call atmegadci_uninit() after atmegadci_init()
172189677Sthompsa		 */
173189677Sthompsa		atmegadci_uninit(&sc->sc_otg);
174189677Sthompsa
175189677Sthompsa		err = bus_teardown_intr(dev, sc->sc_otg.sc_irq_res,
176189677Sthompsa		    sc->sc_otg.sc_intr_hdl);
177189677Sthompsa		sc->sc_otg.sc_intr_hdl = NULL;
178189677Sthompsa	}
179189677Sthompsa	/* free IRQ channel, if any */
180189677Sthompsa	if (sc->sc_otg.sc_irq_res) {
181189677Sthompsa		bus_release_resource(dev, SYS_RES_IRQ, 0,
182189677Sthompsa		    sc->sc_otg.sc_irq_res);
183189677Sthompsa		sc->sc_otg.sc_irq_res = NULL;
184189677Sthompsa	}
185189677Sthompsa	/* free memory resource, if any */
186189677Sthompsa	if (sc->sc_otg.sc_io_res) {
187189677Sthompsa		bus_release_resource(dev, SYS_RES_MEMORY, 0,
188189677Sthompsa		    sc->sc_otg.sc_io_res);
189189677Sthompsa		sc->sc_otg.sc_io_res = NULL;
190189677Sthompsa	}
191194228Sthompsa	usb_bus_mem_free_all(&sc->sc_otg.sc_bus, NULL);
192189677Sthompsa
193189677Sthompsa	return (0);
194189677Sthompsa}
195189677Sthompsa
196189677Sthompsastatic device_method_t atmegadci_methods[] = {
197189677Sthompsa	/* Device interface */
198189677Sthompsa	DEVMETHOD(device_probe, atmegadci_probe),
199189677Sthompsa	DEVMETHOD(device_attach, atmegadci_attach),
200189677Sthompsa	DEVMETHOD(device_detach, atmegadci_detach),
201228483Shselasky	DEVMETHOD(device_suspend, bus_generic_suspend),
202228483Shselasky	DEVMETHOD(device_resume, bus_generic_resume),
203228483Shselasky	DEVMETHOD(device_shutdown, bus_generic_shutdown),
204189677Sthompsa
205227843Smarius	DEVMETHOD_END
206189677Sthompsa};
207189677Sthompsa
208189677Sthompsastatic driver_t atmegadci_driver = {
209228483Shselasky	.name = "atmegadci",
210228483Shselasky	.methods = atmegadci_methods,
211228483Shselasky	.size = sizeof(struct atmegadci_super_softc),
212189677Sthompsa};
213189677Sthompsa
214189677Sthompsastatic devclass_t atmegadci_devclass;
215189677Sthompsa
216189677SthompsaDRIVER_MODULE(atmegadci, atmelarm, atmegadci_driver, atmegadci_devclass, 0, 0);
217189677SthompsaMODULE_DEPEND(atmegadci, usb, 1, 1, 1);
218