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