musb_otg_atmelarm.c revision 187172
1187767Sluigi/* $FreeBSD: head/sys/dev/usb2/controller/musb2_otg_atmelarm.c 187172 2009-01-13 19:03:01Z thompsa $ */ 2187767Sluigi/*- 3187767Sluigi * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. 4187767Sluigi * 5187767Sluigi * Redistribution and use in source and binary forms, with or without 6187767Sluigi * modification, are permitted provided that the following conditions 7187767Sluigi * are met: 8187767Sluigi * 1. Redistributions of source code must retain the above copyright 9187767Sluigi * notice, this list of conditions and the following disclaimer. 10187767Sluigi * 2. Redistributions in binary form must reproduce the above copyright 11187767Sluigi * notice, this list of conditions and the following disclaimer in the 12187767Sluigi * documentation and/or other materials provided with the distribution. 13187767Sluigi * 14187767Sluigi * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15187767Sluigi * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16187767Sluigi * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17187767Sluigi * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18187767Sluigi * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19187767Sluigi * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20187767Sluigi * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21187767Sluigi * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22187767Sluigi * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23187767Sluigi * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24187767Sluigi * SUCH DAMAGE. 25187767Sluigi */ 26187767Sluigi 27187767Sluigi#include <dev/usb2/include/usb2_mfunc.h> 28187767Sluigi#include <dev/usb2/include/usb2_defs.h> 29187767Sluigi#include <dev/usb2/include/usb2_standard.h> 30187767Sluigi 31187767Sluigi#include <dev/usb2/core/usb2_core.h> 32187767Sluigi#include <dev/usb2/core/usb2_busdma.h> 33187767Sluigi#include <dev/usb2/core/usb2_process.h> 34187767Sluigi#include <dev/usb2/core/usb2_sw_transfer.h> 35187767Sluigi#include <dev/usb2/core/usb2_util.h> 36187767Sluigi 37187767Sluigi#include <dev/usb2/controller/usb2_controller.h> 38204591Sluigi#include <dev/usb2/controller/usb2_bus.h> 39187767Sluigi#include <dev/usb2/controller/musb2_otg.h> 40187767Sluigi 41187767Sluigi#include <sys/rman.h> 42187767Sluigi 43187767Sluigistatic device_probe_t musbotg_probe; 44187767Sluigistatic device_attach_t musbotg_attach; 45187767Sluigistatic device_detach_t musbotg_detach; 46187767Sluigistatic device_shutdown_t musbotg_shutdown; 47187767Sluigi 48187767Sluigistruct musbotg_super_softc { 49346205Sae struct musbotg_softc sc_otg; /* must be first */ 50346205Sae}; 51187767Sluigi 52187767Sluigistatic void 53187767Sluigimusbotg_vbus_interrupt(struct musbotg_super_softc *sc) 54187767Sluigi{ 55187767Sluigi uint8_t vbus_val = 1; /* fake VBUS on - TODO */ 56187767Sluigi 57187767Sluigi /* just forward it */ 58187767Sluigi 59332400Sae (sc->sc_otg.sc_bus.methods->vbus_interrupt) 60332400Sae (&sc->sc_otg.sc_bus, vbus_val); 61332400Sae} 62332400Sae 63332400Saestatic void 64332400Saemusbotg_clocks_on(void *arg) 65187767Sluigi{ 66187767Sluigi#if 0 67187767Sluigi struct musbotg_super_softc *sc = arg; 68187767Sluigi 69187767Sluigi#endif 70187767Sluigi} 71187767Sluigi 72187767Sluigistatic void 73187767Sluigimusbotg_clocks_off(void *arg) 74187767Sluigi{ 75187767Sluigi#if 0 76187767Sluigi struct musbotg_super_softc *sc = arg; 77187767Sluigi 78187767Sluigi#endif 79187767Sluigi} 80270424Smelifaro 81270424Smelifarostatic int 82187769Sluigimusbotg_probe(device_t dev) 83187769Sluigi{ 84187769Sluigi device_set_desc(dev, "MUSB OTG integrated USB controller"); 85187769Sluigi return (0); 86187769Sluigi} 87187769Sluigi 88187769Sluigistatic int 89187769Sluigimusbotg_attach(device_t dev) 90332229Stuexen{ 91332229Stuexen struct musbotg_super_softc *sc = device_get_softc(dev); 92187769Sluigi int err; 93187769Sluigi int rid; 94298016Sae 95187769Sluigi if (sc == NULL) { 96204591Sluigi return (ENXIO); 97187769Sluigi } 98204591Sluigi /* setup MUSB OTG USB controller interface softc */ 99204591Sluigi 100187769Sluigi sc->sc_otg.sc_clocks_on = &musbotg_clocks_on; 101187769Sluigi sc->sc_otg.sc_clocks_off = &musbotg_clocks_off; 102187769Sluigi sc->sc_otg.sc_clocks_arg = sc; 103187769Sluigi 104187769Sluigi /* initialise some bus fields */ 105187769Sluigi sc->sc_otg.sc_bus.parent = dev; 106187769Sluigi sc->sc_otg.sc_bus.devices = sc->sc_otg.sc_devices; 107187769Sluigi sc->sc_otg.sc_bus.devices_max = MUSB2_MAX_DEVICES; 108187769Sluigi 109187769Sluigi /* get all DMA memory */ 110187769Sluigi if (usb2_bus_mem_alloc_all(&sc->sc_otg.sc_bus, 111187769Sluigi USB_GET_DMA_TAG(dev), NULL)) { 112190633Spiso return (ENOMEM); 113223666Sae } 114223666Sae rid = 0; 115187769Sluigi sc->sc_otg.sc_io_res = 116187769Sluigi bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 117187769Sluigi 118187769Sluigi if (!(sc->sc_otg.sc_io_res)) { 119187769Sluigi err = ENOMEM; 120187769Sluigi goto error; 121187769Sluigi } 122187769Sluigi sc->sc_otg.sc_io_tag = rman_get_bustag(sc->sc_otg.sc_io_res); 123187769Sluigi sc->sc_otg.sc_io_hdl = rman_get_bushandle(sc->sc_otg.sc_io_res); 124187769Sluigi sc->sc_otg.sc_io_size = rman_get_size(sc->sc_otg.sc_io_res); 125187769Sluigi 126187769Sluigi rid = 0; 127337461Sae sc->sc_otg.sc_irq_res = 128187769Sluigi bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); 129337461Sae if (!(sc->sc_otg.sc_irq_res)) { 130187769Sluigi goto error; 131187769Sluigi } 132187769Sluigi sc->sc_otg.sc_bus.bdev = device_add_child(dev, "usbus", -1); 133187769Sluigi if (!(sc->sc_otg.sc_bus.bdev)) { 134187769Sluigi goto error; 135187769Sluigi } 136187769Sluigi device_set_ivars(sc->sc_otg.sc_bus.bdev, &sc->sc_otg.sc_bus); 137187769Sluigi 138187769Sluigi#if (__FreeBSD_version >= 700031) 139187769Sluigi err = bus_setup_intr(dev, sc->sc_otg.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 140187769Sluigi NULL, (void *)musbotg_interrupt, sc, &sc->sc_otg.sc_intr_hdl); 141187769Sluigi#else 142187769Sluigi err = bus_setup_intr(dev, sc->sc_otg.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 143205169Sluigi (void *)musbotg_interrupt, sc, &sc->sc_otg.sc_intr_hdl); 144187769Sluigi#endif 145187769Sluigi if (err) { 146187769Sluigi sc->sc_otg.sc_intr_hdl = NULL; 147187769Sluigi goto error; 148187769Sluigi } 149187769Sluigi err = musbotg_init(&sc->sc_otg); 150187769Sluigi if (!err) { 151187769Sluigi err = device_probe_and_attach(sc->sc_otg.sc_bus.bdev); 152187769Sluigi } 153187769Sluigi if (err) { 154349573Sae goto error; 155187769Sluigi } else { 156187769Sluigi /* poll VBUS one time */ 157187769Sluigi musbotg_vbus_interrupt(sc); 158187769Sluigi } 159187769Sluigi return (0); 160187769Sluigi 161187769Sluigierror: 162187769Sluigi musbotg_detach(dev); 163187769Sluigi return (ENXIO); 164187769Sluigi} 165187769Sluigi 166187769Sluigistatic int 167187769Sluigimusbotg_detach(device_t dev) 168187769Sluigi{ 169187769Sluigi struct musbotg_super_softc *sc = device_get_softc(dev); 170187769Sluigi device_t bdev; 171187769Sluigi int err; 172187769Sluigi 173187769Sluigi if (sc->sc_otg.sc_bus.bdev) { 174204591Sluigi bdev = sc->sc_otg.sc_bus.bdev; 175204591Sluigi device_detach(bdev); 176187769Sluigi device_delete_child(dev, bdev); 177187769Sluigi } 178204591Sluigi /* during module unload there are lots of children leftover */ 179194930Soleg device_delete_all_children(dev); 180187769Sluigi 181187769Sluigi if (sc->sc_otg.sc_irq_res && sc->sc_otg.sc_intr_hdl) { 182266941Shiren /* 183187769Sluigi * only call musbotg_uninit() after musbotg_init() 184187769Sluigi */ 185300779Struckman musbotg_uninit(&sc->sc_otg); 186300779Struckman 187300779Struckman err = bus_teardown_intr(dev, sc->sc_otg.sc_irq_res, 188300779Struckman sc->sc_otg.sc_intr_hdl); 189300779Struckman sc->sc_otg.sc_intr_hdl = NULL; 190300779Struckman } 191300779Struckman /* free IRQ channel, if any */ 192300779Struckman if (sc->sc_otg.sc_irq_res) { 193300779Struckman bus_release_resource(dev, SYS_RES_IRQ, 0, 194300779Struckman sc->sc_otg.sc_irq_res); 195300779Struckman sc->sc_otg.sc_irq_res = NULL; 196300779Struckman } 197300779Struckman /* free memory resource, if any */ 198300779Struckman if (sc->sc_otg.sc_io_res) { 199300779Struckman bus_release_resource(dev, SYS_RES_MEMORY, 0, 200300779Struckman sc->sc_otg.sc_io_res); 201300779Struckman sc->sc_otg.sc_io_res = NULL; 202300779Struckman } 203300779Struckman usb2_bus_mem_free_all(&sc->sc_otg.sc_bus, NULL); 204300779Struckman 205300779Struckman return (0); 206300779Struckman} 207300779Struckman 208300779Struckmanstatic int 209300779Struckmanmusbotg_shutdown(device_t dev) 210204591Sluigi{ 211187769Sluigi struct musbotg_super_softc *sc = device_get_softc(dev); 212204591Sluigi int err; 213204591Sluigi 214204591Sluigi err = bus_generic_shutdown(dev); 215204591Sluigi if (err) 216204591Sluigi return (err); 217187769Sluigi 218187769Sluigi musbotg_uninit(&sc->sc_otg); 219332210Stuexen 220332210Stuexen return (0); 221332210Stuexen} 222332210Stuexen 223223080Saestatic device_method_t musbotg_methods[] = { 224332210Stuexen /* Device interface */ 225332210Stuexen DEVMETHOD(device_probe, musbotg_probe), 226332210Stuexen DEVMETHOD(device_attach, musbotg_attach), 227187769Sluigi DEVMETHOD(device_detach, musbotg_detach), 228187769Sluigi DEVMETHOD(device_shutdown, musbotg_shutdown), 229220804Sglebius 230187769Sluigi /* Bus interface */ 231187769Sluigi DEVMETHOD(bus_print_child, bus_generic_print_child), 232187769Sluigi 233187769Sluigi {0, 0} 234187769Sluigi}; 235187769Sluigi 236187769Sluigistatic driver_t musbotg_driver = { 237187769Sluigi "musbotg", 238187769Sluigi musbotg_methods, 239187769Sluigi sizeof(struct musbotg_super_softc), 240187769Sluigi}; 241187769Sluigi 242187769Sluigistatic devclass_t musbotg_devclass; 243187769Sluigi 244200567SluigiDRIVER_MODULE(musbotg, atmelarm, musbotg_driver, musbotg_devclass, 0, 0); 245215179SluigiMODULE_DEPEND(musbotg, usb2_controller, 1, 1, 1); 246248552SmelifaroMODULE_DEPEND(musbotg, usb2_core, 1, 1, 1); 247272840Smelifaro