1184610Salfred#include <sys/cdefs.h> 2184610Salfred__FBSDID("$FreeBSD$"); 3184610Salfred 4184610Salfred/*- 5184610Salfred * Copyright (c) 2007-2008 Hans Petter Selasky. All rights reserved. 6184610Salfred * 7184610Salfred * Redistribution and use in source and binary forms, with or without 8184610Salfred * modification, are permitted provided that the following conditions 9184610Salfred * are met: 10184610Salfred * 1. Redistributions of source code must retain the above copyright 11184610Salfred * notice, this list of conditions and the following disclaimer. 12184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 13184610Salfred * notice, this list of conditions and the following disclaimer in the 14184610Salfred * documentation and/or other materials provided with the distribution. 15184610Salfred * 16184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26184610Salfred * SUCH DAMAGE. 27184610Salfred */ 28184610Salfred 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/module.h> 38194677Sthompsa#include <sys/lock.h> 39194677Sthompsa#include <sys/mutex.h> 40194677Sthompsa#include <sys/condvar.h> 41194677Sthompsa#include <sys/sysctl.h> 42194677Sthompsa#include <sys/sx.h> 43194677Sthompsa#include <sys/unistd.h> 44194677Sthompsa#include <sys/callout.h> 45194677Sthompsa#include <sys/malloc.h> 46194677Sthompsa#include <sys/priv.h> 47184610Salfred 48188942Sthompsa#include <dev/usb/usb.h> 49194677Sthompsa#include <dev/usb/usbdi.h> 50184610Salfred 51188942Sthompsa#include <dev/usb/usb_core.h> 52188942Sthompsa#include <dev/usb/usb_busdma.h> 53188942Sthompsa#include <dev/usb/usb_process.h> 54188942Sthompsa#include <dev/usb/usb_util.h> 55184610Salfred 56188942Sthompsa#include <dev/usb/usb_controller.h> 57188942Sthompsa#include <dev/usb/usb_bus.h> 58188942Sthompsa#include <dev/usb/controller/at91dci.h> 59184610Salfred 60184610Salfred#include <sys/rman.h> 61184610Salfred 62184610Salfred#include <arm/at91/at91_pmcvar.h> 63184610Salfred#include <arm/at91/at91rm92reg.h> 64184610Salfred#include <arm/at91/at91_pio_rm9200.h> 65184610Salfred#include <arm/at91/at91_piovar.h> 66184610Salfred 67184610Salfred#define MEM_RID 0 68184610Salfred 69184610Salfred/* Pin Definitions - do they belong here or somewhere else ? */ 70184610Salfred 71184610Salfred#define VBUS_MASK AT91C_PIO_PB24 72184610Salfred#define VBUS_BASE AT91RM92_PIOB_BASE 73184610Salfred 74184610Salfred#define PULLUP_MASK AT91C_PIO_PB22 75184610Salfred#define PULLUP_BASE AT91RM92_PIOB_BASE 76184610Salfred 77184610Salfredstatic device_probe_t at91_udp_probe; 78184610Salfredstatic device_attach_t at91_udp_attach; 79184610Salfredstatic device_detach_t at91_udp_detach; 80184610Salfred 81184610Salfredstruct at91_udp_softc { 82184610Salfred struct at91dci_softc sc_dci; /* must be first */ 83184610Salfred struct at91_pmc_clock *sc_iclk; 84184610Salfred struct at91_pmc_clock *sc_fclk; 85184610Salfred struct resource *sc_vbus_irq_res; 86184610Salfred void *sc_vbus_intr_hdl; 87184610Salfred}; 88184610Salfred 89184610Salfredstatic void 90187175Sthompsaat91_vbus_poll(struct at91_udp_softc *sc) 91184610Salfred{ 92184610Salfred uint32_t temp; 93184610Salfred uint8_t vbus_val; 94184610Salfred 95184610Salfred /* XXX temporary clear interrupts here */ 96184610Salfred 97184610Salfred temp = at91_pio_gpio_clear_interrupt(VBUS_BASE); 98184610Salfred 99184610Salfred /* just forward it */ 100184610Salfred 101184610Salfred vbus_val = at91_pio_gpio_get(VBUS_BASE, VBUS_MASK); 102187175Sthompsa at91dci_vbus_interrupt(&sc->sc_dci, vbus_val); 103184610Salfred} 104184610Salfred 105184610Salfredstatic void 106184610Salfredat91_udp_clocks_on(void *arg) 107184610Salfred{ 108184610Salfred struct at91_udp_softc *sc = arg; 109184610Salfred 110184610Salfred at91_pmc_clock_enable(sc->sc_iclk); 111184610Salfred at91_pmc_clock_enable(sc->sc_fclk); 112184610Salfred} 113184610Salfred 114184610Salfredstatic void 115184610Salfredat91_udp_clocks_off(void *arg) 116184610Salfred{ 117184610Salfred struct at91_udp_softc *sc = arg; 118184610Salfred 119184610Salfred at91_pmc_clock_disable(sc->sc_fclk); 120184610Salfred at91_pmc_clock_disable(sc->sc_iclk); 121184610Salfred} 122184610Salfred 123184610Salfredstatic void 124184610Salfredat91_udp_pull_up(void *arg) 125184610Salfred{ 126184610Salfred at91_pio_gpio_set(PULLUP_BASE, PULLUP_MASK); 127184610Salfred} 128184610Salfred 129184610Salfredstatic void 130184610Salfredat91_udp_pull_down(void *arg) 131184610Salfred{ 132184610Salfred at91_pio_gpio_clear(PULLUP_BASE, PULLUP_MASK); 133184610Salfred} 134184610Salfred 135184610Salfredstatic int 136184610Salfredat91_udp_probe(device_t dev) 137184610Salfred{ 138184610Salfred device_set_desc(dev, "AT91 integrated AT91_UDP controller"); 139184610Salfred return (0); 140184610Salfred} 141184610Salfred 142184610Salfredstatic int 143184610Salfredat91_udp_attach(device_t dev) 144184610Salfred{ 145184610Salfred struct at91_udp_softc *sc = device_get_softc(dev); 146184610Salfred int err; 147184610Salfred int rid; 148184610Salfred 149184610Salfred /* setup AT9100 USB device controller interface softc */ 150184610Salfred 151184610Salfred sc->sc_dci.sc_clocks_on = &at91_udp_clocks_on; 152184610Salfred sc->sc_dci.sc_clocks_off = &at91_udp_clocks_off; 153184610Salfred sc->sc_dci.sc_clocks_arg = sc; 154184610Salfred sc->sc_dci.sc_pull_up = &at91_udp_pull_up; 155184610Salfred sc->sc_dci.sc_pull_down = &at91_udp_pull_down; 156184610Salfred sc->sc_dci.sc_pull_arg = sc; 157184610Salfred 158187170Sthompsa /* initialise some bus fields */ 159187170Sthompsa sc->sc_dci.sc_bus.parent = dev; 160187170Sthompsa sc->sc_dci.sc_bus.devices = sc->sc_dci.sc_devices; 161187170Sthompsa sc->sc_dci.sc_bus.devices_max = AT91_MAX_DEVICES; 162187170Sthompsa 163184610Salfred /* get all DMA memory */ 164194228Sthompsa if (usb_bus_mem_alloc_all(&sc->sc_dci.sc_bus, 165184610Salfred USB_GET_DMA_TAG(dev), NULL)) { 166184610Salfred return (ENOMEM); 167184610Salfred } 168184610Salfred /* 169184610Salfred * configure VBUS input pin, enable deglitch and enable 170184610Salfred * interrupt : 171184610Salfred */ 172184610Salfred at91_pio_use_gpio(VBUS_BASE, VBUS_MASK); 173184610Salfred at91_pio_gpio_input(VBUS_BASE, VBUS_MASK); 174184610Salfred at91_pio_gpio_set_deglitch(VBUS_BASE, VBUS_MASK, 1); 175184610Salfred at91_pio_gpio_set_interrupt(VBUS_BASE, VBUS_MASK, 1); 176184610Salfred 177184610Salfred /* 178184610Salfred * configure PULLUP output pin : 179184610Salfred */ 180184610Salfred at91_pio_use_gpio(PULLUP_BASE, PULLUP_MASK); 181184610Salfred at91_pio_gpio_output(PULLUP_BASE, PULLUP_MASK, 0); 182184610Salfred 183184610Salfred at91_udp_pull_down(sc); 184184610Salfred 185184610Salfred /* wait 10ms for pulldown to stabilise */ 186194228Sthompsa usb_pause_mtx(NULL, hz / 100); 187184610Salfred 188184610Salfred sc->sc_iclk = at91_pmc_clock_ref("udc_clk"); 189184610Salfred sc->sc_fclk = at91_pmc_clock_ref("udpck"); 190184610Salfred 191184610Salfred rid = MEM_RID; 192184610Salfred sc->sc_dci.sc_io_res = 193184610Salfred bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 194184610Salfred 195184610Salfred if (!(sc->sc_dci.sc_io_res)) { 196184610Salfred err = ENOMEM; 197184610Salfred goto error; 198184610Salfred } 199184610Salfred sc->sc_dci.sc_io_tag = rman_get_bustag(sc->sc_dci.sc_io_res); 200184610Salfred sc->sc_dci.sc_io_hdl = rman_get_bushandle(sc->sc_dci.sc_io_res); 201184610Salfred sc->sc_dci.sc_io_size = rman_get_size(sc->sc_dci.sc_io_res); 202184610Salfred 203184610Salfred rid = 0; 204184610Salfred sc->sc_dci.sc_irq_res = 205184610Salfred bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); 206184610Salfred if (!(sc->sc_dci.sc_irq_res)) { 207184610Salfred goto error; 208184610Salfred } 209184610Salfred rid = 1; 210184610Salfred sc->sc_vbus_irq_res = 211184610Salfred bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); 212184610Salfred if (!(sc->sc_vbus_irq_res)) { 213184610Salfred goto error; 214184610Salfred } 215184610Salfred sc->sc_dci.sc_bus.bdev = device_add_child(dev, "usbus", -1); 216184610Salfred if (!(sc->sc_dci.sc_bus.bdev)) { 217184610Salfred goto error; 218184610Salfred } 219184610Salfred device_set_ivars(sc->sc_dci.sc_bus.bdev, &sc->sc_dci.sc_bus); 220184610Salfred 221184610Salfred#if (__FreeBSD_version >= 700031) 222184610Salfred err = bus_setup_intr(dev, sc->sc_dci.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 223190183Sthompsa NULL, (driver_intr_t *)at91dci_interrupt, sc, &sc->sc_dci.sc_intr_hdl); 224184610Salfred#else 225184610Salfred err = bus_setup_intr(dev, sc->sc_dci.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 226190183Sthompsa (driver_intr_t *)at91dci_interrupt, sc, &sc->sc_dci.sc_intr_hdl); 227184610Salfred#endif 228184610Salfred if (err) { 229184610Salfred sc->sc_dci.sc_intr_hdl = NULL; 230184610Salfred goto error; 231184610Salfred } 232184610Salfred#if (__FreeBSD_version >= 700031) 233184610Salfred err = bus_setup_intr(dev, sc->sc_vbus_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 234190183Sthompsa NULL, (driver_intr_t *)at91_vbus_poll, sc, &sc->sc_vbus_intr_hdl); 235184610Salfred#else 236184610Salfred err = bus_setup_intr(dev, sc->sc_vbus_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, 237190183Sthompsa (driver_intr_t *)at91_vbus_poll, sc, &sc->sc_vbus_intr_hdl); 238184610Salfred#endif 239184610Salfred if (err) { 240184610Salfred sc->sc_vbus_intr_hdl = NULL; 241184610Salfred goto error; 242184610Salfred } 243184610Salfred err = at91dci_init(&sc->sc_dci); 244184610Salfred if (!err) { 245184610Salfred err = device_probe_and_attach(sc->sc_dci.sc_bus.bdev); 246184610Salfred } 247184610Salfred if (err) { 248184610Salfred goto error; 249184610Salfred } else { 250184610Salfred /* poll VBUS one time */ 251187175Sthompsa at91_vbus_poll(sc); 252184610Salfred } 253184610Salfred return (0); 254184610Salfred 255184610Salfrederror: 256184610Salfred at91_udp_detach(dev); 257184610Salfred return (ENXIO); 258184610Salfred} 259184610Salfred 260184610Salfredstatic int 261184610Salfredat91_udp_detach(device_t dev) 262184610Salfred{ 263184610Salfred struct at91_udp_softc *sc = device_get_softc(dev); 264184610Salfred device_t bdev; 265184610Salfred int err; 266184610Salfred 267184610Salfred if (sc->sc_dci.sc_bus.bdev) { 268184610Salfred bdev = sc->sc_dci.sc_bus.bdev; 269184610Salfred device_detach(bdev); 270184610Salfred device_delete_child(dev, bdev); 271184610Salfred } 272184610Salfred /* during module unload there are lots of children leftover */ 273229118Shselasky device_delete_children(dev); 274184610Salfred 275184610Salfred /* disable Transceiver */ 276184610Salfred AT91_UDP_WRITE_4(&sc->sc_dci, AT91_UDP_TXVC, AT91_UDP_TXVC_DIS); 277184610Salfred 278184610Salfred /* disable and clear all interrupts */ 279184610Salfred AT91_UDP_WRITE_4(&sc->sc_dci, AT91_UDP_IDR, 0xFFFFFFFF); 280184610Salfred AT91_UDP_WRITE_4(&sc->sc_dci, AT91_UDP_ICR, 0xFFFFFFFF); 281184610Salfred 282184610Salfred /* disable VBUS interrupt */ 283184610Salfred at91_pio_gpio_set_interrupt(VBUS_BASE, VBUS_MASK, 0); 284184610Salfred 285184610Salfred if (sc->sc_vbus_irq_res && sc->sc_vbus_intr_hdl) { 286184610Salfred err = bus_teardown_intr(dev, sc->sc_vbus_irq_res, 287184610Salfred sc->sc_vbus_intr_hdl); 288184610Salfred sc->sc_vbus_intr_hdl = NULL; 289184610Salfred } 290184610Salfred if (sc->sc_vbus_irq_res) { 291184610Salfred bus_release_resource(dev, SYS_RES_IRQ, 1, 292184610Salfred sc->sc_vbus_irq_res); 293184610Salfred sc->sc_vbus_irq_res = NULL; 294184610Salfred } 295184610Salfred if (sc->sc_dci.sc_irq_res && sc->sc_dci.sc_intr_hdl) { 296184610Salfred /* 297184610Salfred * only call at91_udp_uninit() after at91_udp_init() 298184610Salfred */ 299184610Salfred at91dci_uninit(&sc->sc_dci); 300184610Salfred 301184610Salfred err = bus_teardown_intr(dev, sc->sc_dci.sc_irq_res, 302184610Salfred sc->sc_dci.sc_intr_hdl); 303184610Salfred sc->sc_dci.sc_intr_hdl = NULL; 304184610Salfred } 305184610Salfred if (sc->sc_dci.sc_irq_res) { 306184610Salfred bus_release_resource(dev, SYS_RES_IRQ, 0, 307184610Salfred sc->sc_dci.sc_irq_res); 308184610Salfred sc->sc_dci.sc_irq_res = NULL; 309184610Salfred } 310184610Salfred if (sc->sc_dci.sc_io_res) { 311184610Salfred bus_release_resource(dev, SYS_RES_MEMORY, MEM_RID, 312184610Salfred sc->sc_dci.sc_io_res); 313184610Salfred sc->sc_dci.sc_io_res = NULL; 314184610Salfred } 315194228Sthompsa usb_bus_mem_free_all(&sc->sc_dci.sc_bus, NULL); 316184610Salfred 317184610Salfred /* disable clocks */ 318184610Salfred at91_pmc_clock_disable(sc->sc_iclk); 319184610Salfred at91_pmc_clock_disable(sc->sc_fclk); 320184610Salfred at91_pmc_clock_deref(sc->sc_fclk); 321184610Salfred at91_pmc_clock_deref(sc->sc_iclk); 322184610Salfred 323184610Salfred return (0); 324184610Salfred} 325184610Salfred 326184610Salfredstatic device_method_t at91_udp_methods[] = { 327184610Salfred /* Device interface */ 328184610Salfred DEVMETHOD(device_probe, at91_udp_probe), 329184610Salfred DEVMETHOD(device_attach, at91_udp_attach), 330184610Salfred DEVMETHOD(device_detach, at91_udp_detach), 331229096Shselasky DEVMETHOD(device_suspend, bus_generic_suspend), 332229096Shselasky DEVMETHOD(device_resume, bus_generic_resume), 333229096Shselasky DEVMETHOD(device_shutdown, bus_generic_shutdown), 334184610Salfred 335229093Shselasky DEVMETHOD_END 336184610Salfred}; 337184610Salfred 338184610Salfredstatic driver_t at91_udp_driver = { 339229096Shselasky .name = "at91_udp", 340229096Shselasky .methods = at91_udp_methods, 341229096Shselasky .size = sizeof(struct at91_udp_softc), 342184610Salfred}; 343184610Salfred 344184610Salfredstatic devclass_t at91_udp_devclass; 345184610Salfred 346184610SalfredDRIVER_MODULE(at91_udp, atmelarm, at91_udp_driver, at91_udp_devclass, 0, 0); 347