atmegadci_atmelarm.c revision 194677
165557Sjasone#include <sys/cdefs.h> 2132637Simp__FBSDID("$FreeBSD: head/sys/dev/usb/controller/atmegadci_atmelarm.c 194677 2009-06-23 02:19:59Z thompsa $"); 365557Sjasone 4132637Simp/*- 5132637Simp * Copyright (c) 2009 Hans Petter Selasky. All rights reserved. 6132637Simp * 7132637Simp * Redistribution and use in source and binary forms, with or without 8132637Simp * modification, are permitted provided that the following conditions 9132637Simp * are met: 10132637Simp * 1. Redistributions of source code must retain the above copyright 11132637Simp * notice, this list of conditions and the following disclaimer. 12132637Simp * 2. Redistributions in binary form must reproduce the above copyright 13132637Simp * notice, this list of conditions and the following disclaimer in the 14132637Simp * documentation and/or other materials provided with the distribution. 15132637Simp * 16132637Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17132637Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18132637Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19132637Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20132637Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21132637Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22132637Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23132637Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2465557Sjasone * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2565557Sjasone * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26116182Sobrien * SUCH DAMAGE. 27116182Sobrien */ 28116182Sobrien 2965557Sjasone#include <sys/stdint.h> 3065557Sjasone#include <sys/stddef.h> 3165557Sjasone#include <sys/param.h> 3276440Sjhb#include <sys/queue.h> 3376166Smarkm#include <sys/types.h> 3476166Smarkm#include <sys/systm.h> 3576166Smarkm#include <sys/kernel.h> 3676440Sjhb#include <sys/bus.h> 37104964Sjeff#include <sys/linker_set.h> 3865557Sjasone#include <sys/module.h> 39134591Sjulian#include <sys/lock.h> 40134591Sjulian#include <sys/mutex.h> 41134591Sjulian#include <sys/condvar.h> 4265557Sjasone#include <sys/sysctl.h> 4365557Sjasone#include <sys/sx.h> 44177253Srwatson#include <sys/unistd.h> 4565557Sjasone#include <sys/callout.h> 4665557Sjasone#include <sys/malloc.h> 47121238Speter#include <sys/priv.h> 4872222Sjhb 4972222Sjhb#include <dev/usb/usb.h> 5065557Sjasone#include <dev/usb/usbdi.h> 5165557Sjasone 5265557Sjasone#include <dev/usb/usb_core.h> 5365557Sjasone#include <dev/usb/usb_busdma.h> 5476078Sjhb#include <dev/usb/usb_process.h> 5587702Sjhb#include <dev/usb/usb_util.h> 5676078Sjhb 5776078Sjhb#include <dev/usb/usb_controller.h> 5899072Sjulian#include <dev/usb/usb_bus.h> 5965557Sjasone#include <dev/usb/controller/atmegadci.h> 6065557Sjasone 61173050Sjulian#include <sys/rman.h> 6276078Sjhb 63222531Snwhitehornstatic device_probe_t atmegadci_probe; 64173004Sjulianstatic device_attach_t atmegadci_attach; 65173035Sjulianstatic device_detach_t atmegadci_detach; 66173004Sjulianstatic device_shutdown_t atmegadci_shutdown; 67173051Sjulian 68173004Sjulianstruct atmegadci_super_softc { 6965557Sjasone struct atmegadci_softc sc_otg; /* must be first */ 70173035Sjulian}; 71173051Sjulian 72173004Sjulianstatic void 7365557Sjasoneatmegadci_clocks_on(struct usb_bus *bus) 7465557Sjasone{ 75172836Sjulian /* TODO */ 7665557Sjasone} 77170307Sjeff 78131473Sjhbstatic void 79198854Sattilioatmegadci_clocks_off(struct usb_bus *bus) 80163709Sjb{ 81141246Sssouhlal /* TODO */ 82170307Sjeff} 8376078Sjhb 8465557Sjasonestatic int 8576078Sjhbatmegadci_probe(device_t dev) 8665557Sjasone{ 87 device_set_desc(dev, "ATMEL OTG integrated USB controller"); 88 return (0); 89} 90 91static int 92atmegadci_attach(device_t dev) 93{ 94 struct atmegadci_super_softc *sc = device_get_softc(dev); 95 int err; 96 int rid; 97 98 /* setup MUSB OTG USB controller interface softc */ 99 sc->sc_otg.sc_clocks_on = &atmegadci_clocks_on; 100 sc->sc_otg.sc_clocks_off = &atmegadci_clocks_off; 101 102 /* initialise some bus fields */ 103 sc->sc_otg.sc_bus.parent = dev; 104 sc->sc_otg.sc_bus.devices = sc->sc_otg.sc_devices; 105 sc->sc_otg.sc_bus.devices_max = ATMEGA_MAX_DEVICES; 106 107 /* get all DMA memory */ 108 if (usb_bus_mem_alloc_all(&sc->sc_otg.sc_bus, 109 USB_GET_DMA_TAG(dev), NULL)) { 110 return (ENOMEM); 111 } 112 rid = 0; 113 sc->sc_otg.sc_io_res = 114 bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 115 116 if (!(sc->sc_otg.sc_io_res)) { 117 err = ENOMEM; 118 goto error; 119 } 120 sc->sc_otg.sc_io_tag = rman_get_bustag(sc->sc_otg.sc_io_res); 121 sc->sc_otg.sc_io_hdl = rman_get_bushandle(sc->sc_otg.sc_io_res); 122 123 rid = 0; 124 sc->sc_otg.sc_irq_res = 125 bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); 126 if (!(sc->sc_otg.sc_irq_res)) { 127 goto error; 128 } 129 sc->sc_otg.sc_bus.bdev = device_add_child(dev, "usbus", -1); 130 if (!(sc->sc_otg.sc_bus.bdev)) { 131 goto error; 132 } 133 device_set_ivars(sc->sc_otg.sc_bus.bdev, &sc->sc_otg.sc_bus); 134 135 err = bus_setup_intr(dev, sc->sc_otg.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 136 NULL, (driver_intr_t *)atmegadci_interrupt, sc, &sc->sc_otg.sc_intr_hdl); 137 if (err) { 138 sc->sc_otg.sc_intr_hdl = NULL; 139 goto error; 140 } 141 err = atmegadci_init(&sc->sc_otg); 142 if (!err) { 143 err = device_probe_and_attach(sc->sc_otg.sc_bus.bdev); 144 } 145 if (err) { 146 goto error; 147 } 148 return (0); 149 150error: 151 atmegadci_detach(dev); 152 return (ENXIO); 153} 154 155static int 156atmegadci_detach(device_t dev) 157{ 158 struct atmegadci_super_softc *sc = device_get_softc(dev); 159 device_t bdev; 160 int err; 161 162 if (sc->sc_otg.sc_bus.bdev) { 163 bdev = sc->sc_otg.sc_bus.bdev; 164 device_detach(bdev); 165 device_delete_child(dev, bdev); 166 } 167 /* during module unload there are lots of children leftover */ 168 device_delete_all_children(dev); 169 170 if (sc->sc_otg.sc_irq_res && sc->sc_otg.sc_intr_hdl) { 171 /* 172 * only call atmegadci_uninit() after atmegadci_init() 173 */ 174 atmegadci_uninit(&sc->sc_otg); 175 176 err = bus_teardown_intr(dev, sc->sc_otg.sc_irq_res, 177 sc->sc_otg.sc_intr_hdl); 178 sc->sc_otg.sc_intr_hdl = NULL; 179 } 180 /* free IRQ channel, if any */ 181 if (sc->sc_otg.sc_irq_res) { 182 bus_release_resource(dev, SYS_RES_IRQ, 0, 183 sc->sc_otg.sc_irq_res); 184 sc->sc_otg.sc_irq_res = NULL; 185 } 186 /* free memory resource, if any */ 187 if (sc->sc_otg.sc_io_res) { 188 bus_release_resource(dev, SYS_RES_MEMORY, 0, 189 sc->sc_otg.sc_io_res); 190 sc->sc_otg.sc_io_res = NULL; 191 } 192 usb_bus_mem_free_all(&sc->sc_otg.sc_bus, NULL); 193 194 return (0); 195} 196 197static int 198atmegadci_shutdown(device_t dev) 199{ 200 struct atmegadci_super_softc *sc = device_get_softc(dev); 201 int err; 202 203 err = bus_generic_shutdown(dev); 204 if (err) 205 return (err); 206 207 atmegadci_uninit(&sc->sc_otg); 208 209 return (0); 210} 211 212static device_method_t atmegadci_methods[] = { 213 /* Device interface */ 214 DEVMETHOD(device_probe, atmegadci_probe), 215 DEVMETHOD(device_attach, atmegadci_attach), 216 DEVMETHOD(device_detach, atmegadci_detach), 217 DEVMETHOD(device_shutdown, atmegadci_shutdown), 218 219 /* Bus interface */ 220 DEVMETHOD(bus_print_child, bus_generic_print_child), 221 222 {0, 0} 223}; 224 225static driver_t atmegadci_driver = { 226 "atmegadci", 227 atmegadci_methods, 228 sizeof(struct atmegadci_super_softc), 229}; 230 231static devclass_t atmegadci_devclass; 232 233DRIVER_MODULE(atmegadci, atmelarm, atmegadci_driver, atmegadci_devclass, 0, 0); 234MODULE_DEPEND(atmegadci, usb, 1, 1, 1); 235