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