musb_otg_atmelarm.c revision 187175
198944Sobrien/* $FreeBSD: head/sys/dev/usb2/controller/musb2_otg_atmelarm.c 187175 2009-01-13 19:03:33Z thompsa $ */
298944Sobrien/*-
3130803Smarcel * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
498944Sobrien *
598944Sobrien * Redistribution and use in source and binary forms, with or without
698944Sobrien * modification, are permitted provided that the following conditions
798944Sobrien * are met:
898944Sobrien * 1. Redistributions of source code must retain the above copyright
998944Sobrien *    notice, this list of conditions and the following disclaimer.
1098944Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1198944Sobrien *    notice, this list of conditions and the following disclaimer in the
1298944Sobrien *    documentation and/or other materials provided with the distribution.
1398944Sobrien *
1498944Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1598944Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1698944Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1798944Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1898944Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1998944Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2098944Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2198944Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2298944Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23130803Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24130803Smarcel * SUCH DAMAGE.
2598944Sobrien */
2698944Sobrien
2798944Sobrien#include <dev/usb2/include/usb2_mfunc.h>
2898944Sobrien#include <dev/usb2/include/usb2_defs.h>
29130803Smarcel#include <dev/usb2/include/usb2_standard.h>
30130803Smarcel
31130803Smarcel#include <dev/usb2/core/usb2_core.h>
32130803Smarcel#include <dev/usb2/core/usb2_busdma.h>
33130803Smarcel#include <dev/usb2/core/usb2_process.h>
34130803Smarcel#include <dev/usb2/core/usb2_sw_transfer.h>
35130803Smarcel#include <dev/usb2/core/usb2_util.h>
3698944Sobrien
37130803Smarcel#include <dev/usb2/controller/usb2_controller.h>
38130803Smarcel#include <dev/usb2/controller/usb2_bus.h>
39130803Smarcel#include <dev/usb2/controller/musb2_otg.h>
4098944Sobrien
4198944Sobrien#include <sys/rman.h>
4298944Sobrien
4398944Sobrienstatic device_probe_t musbotg_probe;
4498944Sobrienstatic device_attach_t musbotg_attach;
4598944Sobrienstatic device_detach_t musbotg_detach;
4698944Sobrienstatic device_shutdown_t musbotg_shutdown;
4798944Sobrien
4898944Sobrienstruct musbotg_super_softc {
49130803Smarcel	struct musbotg_softc sc_otg;	/* must be first */
50130803Smarcel};
51130803Smarcel
52130803Smarcelstatic void
5398944Sobrienmusbotg_vbus_poll(struct musbotg_super_softc *sc)
5498944Sobrien{
5598944Sobrien	uint8_t vbus_val = 1;		/* fake VBUS on - TODO */
5698944Sobrien
57130803Smarcel	/* just forward it */
5898944Sobrien	musbotg_vbus_interrupt(&sc->sc_otg, vbus_val);
5998944Sobrien}
6098944Sobrien
6198944Sobrienstatic void
6298944Sobrienmusbotg_clocks_on(void *arg)
6398944Sobrien{
6498944Sobrien#if 0
6598944Sobrien	struct musbotg_super_softc *sc = arg;
6698944Sobrien
6798944Sobrien#endif
6898944Sobrien}
6998944Sobrien
7098944Sobrienstatic void
7198944Sobrienmusbotg_clocks_off(void *arg)
7298944Sobrien{
7398944Sobrien#if 0
7498944Sobrien	struct musbotg_super_softc *sc = arg;
7598944Sobrien
7698944Sobrien#endif
7798944Sobrien}
7898944Sobrien
7998944Sobrienstatic int
8098944Sobrienmusbotg_probe(device_t dev)
8198944Sobrien{
8298944Sobrien	device_set_desc(dev, "MUSB OTG integrated USB controller");
83130803Smarcel	return (0);
84130803Smarcel}
85130803Smarcel
86130803Smarcelstatic int
8798944Sobrienmusbotg_attach(device_t dev)
88130803Smarcel{
89130803Smarcel	struct musbotg_super_softc *sc = device_get_softc(dev);
90130803Smarcel	int err;
91130803Smarcel	int rid;
9298944Sobrien
93130803Smarcel	if (sc == NULL) {
94130803Smarcel		return (ENXIO);
95130803Smarcel	}
9698944Sobrien	/* setup MUSB OTG USB controller interface softc */
9798944Sobrien
9898944Sobrien	sc->sc_otg.sc_clocks_on = &musbotg_clocks_on;
9998944Sobrien	sc->sc_otg.sc_clocks_off = &musbotg_clocks_off;
10098944Sobrien	sc->sc_otg.sc_clocks_arg = sc;
10198944Sobrien
10298944Sobrien	/* initialise some bus fields */
10398944Sobrien	sc->sc_otg.sc_bus.parent = dev;
10498944Sobrien	sc->sc_otg.sc_bus.devices = sc->sc_otg.sc_devices;
10598944Sobrien	sc->sc_otg.sc_bus.devices_max = MUSB2_MAX_DEVICES;
10698944Sobrien
10798944Sobrien	/* get all DMA memory */
10898944Sobrien	if (usb2_bus_mem_alloc_all(&sc->sc_otg.sc_bus,
10998944Sobrien	    USB_GET_DMA_TAG(dev), NULL)) {
11098944Sobrien		return (ENOMEM);
11198944Sobrien	}
11298944Sobrien	rid = 0;
11398944Sobrien	sc->sc_otg.sc_io_res =
11498944Sobrien	    bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
11598944Sobrien
11698944Sobrien	if (!(sc->sc_otg.sc_io_res)) {
11798944Sobrien		err = ENOMEM;
11898944Sobrien		goto error;
11998944Sobrien	}
12098944Sobrien	sc->sc_otg.sc_io_tag = rman_get_bustag(sc->sc_otg.sc_io_res);
12198944Sobrien	sc->sc_otg.sc_io_hdl = rman_get_bushandle(sc->sc_otg.sc_io_res);
12298944Sobrien	sc->sc_otg.sc_io_size = rman_get_size(sc->sc_otg.sc_io_res);
12398944Sobrien
12498944Sobrien	rid = 0;
12598944Sobrien	sc->sc_otg.sc_irq_res =
12698944Sobrien	    bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
12798944Sobrien	if (!(sc->sc_otg.sc_irq_res)) {
12898944Sobrien		goto error;
12998944Sobrien	}
13098944Sobrien	sc->sc_otg.sc_bus.bdev = device_add_child(dev, "usbus", -1);
13198944Sobrien	if (!(sc->sc_otg.sc_bus.bdev)) {
13298944Sobrien		goto error;
13398944Sobrien	}
13498944Sobrien	device_set_ivars(sc->sc_otg.sc_bus.bdev, &sc->sc_otg.sc_bus);
13598944Sobrien
13698944Sobrien#if (__FreeBSD_version >= 700031)
13798944Sobrien	err = bus_setup_intr(dev, sc->sc_otg.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
13898944Sobrien	    NULL, (void *)musbotg_interrupt, sc, &sc->sc_otg.sc_intr_hdl);
13998944Sobrien#else
14098944Sobrien	err = bus_setup_intr(dev, sc->sc_otg.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
14198944Sobrien	    (void *)musbotg_interrupt, sc, &sc->sc_otg.sc_intr_hdl);
14298944Sobrien#endif
14398944Sobrien	if (err) {
14498944Sobrien		sc->sc_otg.sc_intr_hdl = NULL;
14598944Sobrien		goto error;
14698944Sobrien	}
14798944Sobrien	err = musbotg_init(&sc->sc_otg);
14898944Sobrien	if (!err) {
14998944Sobrien		err = device_probe_and_attach(sc->sc_otg.sc_bus.bdev);
15098944Sobrien	}
15198944Sobrien	if (err) {
15298944Sobrien		goto error;
15398944Sobrien	} else {
15498944Sobrien		/* poll VBUS one time */
15598944Sobrien		musbotg_vbus_poll(sc);
15698944Sobrien	}
15798944Sobrien	return (0);
15898944Sobrien
15998944Sobrienerror:
16098944Sobrien	musbotg_detach(dev);
16198944Sobrien	return (ENXIO);
16298944Sobrien}
16398944Sobrien
16498944Sobrienstatic int
16598944Sobrienmusbotg_detach(device_t dev)
16698944Sobrien{
16798944Sobrien	struct musbotg_super_softc *sc = device_get_softc(dev);
16898944Sobrien	device_t bdev;
16998944Sobrien	int err;
17098944Sobrien
17198944Sobrien	if (sc->sc_otg.sc_bus.bdev) {
17298944Sobrien		bdev = sc->sc_otg.sc_bus.bdev;
17398944Sobrien		device_detach(bdev);
17498944Sobrien		device_delete_child(dev, bdev);
17598944Sobrien	}
17698944Sobrien	/* during module unload there are lots of children leftover */
17798944Sobrien	device_delete_all_children(dev);
17898944Sobrien
17998944Sobrien	if (sc->sc_otg.sc_irq_res && sc->sc_otg.sc_intr_hdl) {
18098944Sobrien		/*
18198944Sobrien		 * only call musbotg_uninit() after musbotg_init()
18298944Sobrien		 */
18398944Sobrien		musbotg_uninit(&sc->sc_otg);
18498944Sobrien
18598944Sobrien		err = bus_teardown_intr(dev, sc->sc_otg.sc_irq_res,
18698944Sobrien		    sc->sc_otg.sc_intr_hdl);
18798944Sobrien		sc->sc_otg.sc_intr_hdl = NULL;
18898944Sobrien	}
18998944Sobrien	/* free IRQ channel, if any */
19098944Sobrien	if (sc->sc_otg.sc_irq_res) {
19198944Sobrien		bus_release_resource(dev, SYS_RES_IRQ, 0,
19298944Sobrien		    sc->sc_otg.sc_irq_res);
19398944Sobrien		sc->sc_otg.sc_irq_res = NULL;
19498944Sobrien	}
19598944Sobrien	/* free memory resource, if any */
19698944Sobrien	if (sc->sc_otg.sc_io_res) {
19798944Sobrien		bus_release_resource(dev, SYS_RES_MEMORY, 0,
19898944Sobrien		    sc->sc_otg.sc_io_res);
19998944Sobrien		sc->sc_otg.sc_io_res = NULL;
20098944Sobrien	}
20198944Sobrien	usb2_bus_mem_free_all(&sc->sc_otg.sc_bus, NULL);
20298944Sobrien
20398944Sobrien	return (0);
20498944Sobrien}
20598944Sobrien
20698944Sobrienstatic int
20798944Sobrienmusbotg_shutdown(device_t dev)
20898944Sobrien{
20998944Sobrien	struct musbotg_super_softc *sc = device_get_softc(dev);
21098944Sobrien	int err;
21198944Sobrien
21298944Sobrien	err = bus_generic_shutdown(dev);
21398944Sobrien	if (err)
21498944Sobrien		return (err);
21598944Sobrien
21698944Sobrien	musbotg_uninit(&sc->sc_otg);
21798944Sobrien
21898944Sobrien	return (0);
21998944Sobrien}
22098944Sobrien
22198944Sobrienstatic device_method_t musbotg_methods[] = {
22298944Sobrien	/* Device interface */
22398944Sobrien	DEVMETHOD(device_probe, musbotg_probe),
22498944Sobrien	DEVMETHOD(device_attach, musbotg_attach),
22598944Sobrien	DEVMETHOD(device_detach, musbotg_detach),
22698944Sobrien	DEVMETHOD(device_shutdown, musbotg_shutdown),
22798944Sobrien
22898944Sobrien	/* Bus interface */
22998944Sobrien	DEVMETHOD(bus_print_child, bus_generic_print_child),
230130803Smarcel
23198944Sobrien	{0, 0}
23298944Sobrien};
23398944Sobrien
23498944Sobrienstatic driver_t musbotg_driver = {
23598944Sobrien	"musbotg",
23698944Sobrien	musbotg_methods,
23798944Sobrien	sizeof(struct musbotg_super_softc),
238130803Smarcel};
239130803Smarcel
240130803Smarcelstatic devclass_t musbotg_devclass;
241130803Smarcel
242130803SmarcelDRIVER_MODULE(musbotg, atmelarm, musbotg_driver, musbotg_devclass, 0, 0);
243130803SmarcelMODULE_DEPEND(musbotg, usb2_controller, 1, 1, 1);
244130803SmarcelMODULE_DEPEND(musbotg, usb2_core, 1, 1, 1);
245130803Smarcel