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> 64238848Simp#include <arm/at91/at91_pioreg.h> 65184610Salfred#include <arm/at91/at91_piovar.h> 66184610Salfred 67184610Salfred#define MEM_RID 0 68184610Salfred 69238848Simp/* Pin Definitions - do they belong here or somewhere else ? -- YES! */ 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 */ 83239531Shselasky struct at91_pmc_clock *sc_mclk; 84184610Salfred struct at91_pmc_clock *sc_iclk; 85184610Salfred struct at91_pmc_clock *sc_fclk; 86240314Shselasky struct callout sc_vbus; 87184610Salfred}; 88184610Salfred 89184610Salfredstatic void 90187175Sthompsaat91_vbus_poll(struct at91_udp_softc *sc) 91184610Salfred{ 92184610Salfred uint8_t vbus_val; 93184610Salfred 94249232Shselasky vbus_val = at91_pio_gpio_get(VBUS_BASE, VBUS_MASK) != 0; 95187175Sthompsa at91dci_vbus_interrupt(&sc->sc_dci, vbus_val); 96240314Shselasky 97240314Shselasky callout_reset(&sc->sc_vbus, hz, (void *)&at91_vbus_poll, sc); 98184610Salfred} 99184610Salfred 100184610Salfredstatic void 101184610Salfredat91_udp_clocks_on(void *arg) 102184610Salfred{ 103184610Salfred struct at91_udp_softc *sc = arg; 104184610Salfred 105239531Shselasky at91_pmc_clock_enable(sc->sc_mclk); 106184610Salfred at91_pmc_clock_enable(sc->sc_iclk); 107184610Salfred at91_pmc_clock_enable(sc->sc_fclk); 108184610Salfred} 109184610Salfred 110184610Salfredstatic void 111184610Salfredat91_udp_clocks_off(void *arg) 112184610Salfred{ 113184610Salfred struct at91_udp_softc *sc = arg; 114184610Salfred 115184610Salfred at91_pmc_clock_disable(sc->sc_fclk); 116184610Salfred at91_pmc_clock_disable(sc->sc_iclk); 117239531Shselasky at91_pmc_clock_disable(sc->sc_mclk); 118184610Salfred} 119184610Salfred 120184610Salfredstatic void 121184610Salfredat91_udp_pull_up(void *arg) 122184610Salfred{ 123184610Salfred at91_pio_gpio_set(PULLUP_BASE, PULLUP_MASK); 124184610Salfred} 125184610Salfred 126184610Salfredstatic void 127184610Salfredat91_udp_pull_down(void *arg) 128184610Salfred{ 129184610Salfred at91_pio_gpio_clear(PULLUP_BASE, PULLUP_MASK); 130184610Salfred} 131184610Salfred 132184610Salfredstatic int 133184610Salfredat91_udp_probe(device_t dev) 134184610Salfred{ 135184610Salfred device_set_desc(dev, "AT91 integrated AT91_UDP controller"); 136184610Salfred return (0); 137184610Salfred} 138184610Salfred 139184610Salfredstatic int 140184610Salfredat91_udp_attach(device_t dev) 141184610Salfred{ 142184610Salfred struct at91_udp_softc *sc = device_get_softc(dev); 143184610Salfred int err; 144184610Salfred int rid; 145184610Salfred 146184610Salfred /* setup AT9100 USB device controller interface softc */ 147184610Salfred 148184610Salfred sc->sc_dci.sc_clocks_on = &at91_udp_clocks_on; 149184610Salfred sc->sc_dci.sc_clocks_off = &at91_udp_clocks_off; 150184610Salfred sc->sc_dci.sc_clocks_arg = sc; 151184610Salfred sc->sc_dci.sc_pull_up = &at91_udp_pull_up; 152184610Salfred sc->sc_dci.sc_pull_down = &at91_udp_pull_down; 153184610Salfred sc->sc_dci.sc_pull_arg = sc; 154184610Salfred 155187170Sthompsa /* initialise some bus fields */ 156187170Sthompsa sc->sc_dci.sc_bus.parent = dev; 157187170Sthompsa sc->sc_dci.sc_bus.devices = sc->sc_dci.sc_devices; 158187170Sthompsa sc->sc_dci.sc_bus.devices_max = AT91_MAX_DEVICES; 159187170Sthompsa 160184610Salfred /* get all DMA memory */ 161194228Sthompsa if (usb_bus_mem_alloc_all(&sc->sc_dci.sc_bus, 162184610Salfred USB_GET_DMA_TAG(dev), NULL)) { 163184610Salfred return (ENOMEM); 164184610Salfred } 165240314Shselasky callout_init_mtx(&sc->sc_vbus, &sc->sc_dci.sc_bus.bus_mtx, 0); 166240314Shselasky 167184610Salfred /* 168184610Salfred * configure VBUS input pin, enable deglitch and enable 169184610Salfred * interrupt : 170184610Salfred */ 171184610Salfred at91_pio_use_gpio(VBUS_BASE, VBUS_MASK); 172184610Salfred at91_pio_gpio_input(VBUS_BASE, VBUS_MASK); 173184610Salfred at91_pio_gpio_set_deglitch(VBUS_BASE, VBUS_MASK, 1); 174240314Shselasky at91_pio_gpio_set_interrupt(VBUS_BASE, VBUS_MASK, 0); 175184610Salfred 176184610Salfred /* 177184610Salfred * configure PULLUP output pin : 178184610Salfred */ 179184610Salfred at91_pio_use_gpio(PULLUP_BASE, PULLUP_MASK); 180184610Salfred at91_pio_gpio_output(PULLUP_BASE, PULLUP_MASK, 0); 181184610Salfred 182184610Salfred at91_udp_pull_down(sc); 183184610Salfred 184184610Salfred /* wait 10ms for pulldown to stabilise */ 185194228Sthompsa usb_pause_mtx(NULL, hz / 100); 186184610Salfred 187239531Shselasky sc->sc_mclk = at91_pmc_clock_ref("mck"); 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 sc->sc_dci.sc_bus.bdev = device_add_child(dev, "usbus", -1); 210184610Salfred if (!(sc->sc_dci.sc_bus.bdev)) { 211184610Salfred goto error; 212184610Salfred } 213184610Salfred device_set_ivars(sc->sc_dci.sc_bus.bdev, &sc->sc_dci.sc_bus); 214184610Salfred 215269916Shselasky err = bus_setup_intr(dev, sc->sc_dci.sc_irq_res, INTR_TYPE_TTY | INTR_MPSAFE, 216269916Shselasky at91dci_filter_interrupt, at91dci_interrupt, sc, &sc->sc_dci.sc_intr_hdl); 217184610Salfred if (err) { 218184610Salfred sc->sc_dci.sc_intr_hdl = NULL; 219184610Salfred goto error; 220184610Salfred } 221240314Shselasky 222184610Salfred err = at91dci_init(&sc->sc_dci); 223184610Salfred if (!err) { 224184610Salfred err = device_probe_and_attach(sc->sc_dci.sc_bus.bdev); 225184610Salfred } 226184610Salfred if (err) { 227184610Salfred goto error; 228184610Salfred } else { 229184610Salfred /* poll VBUS one time */ 230240314Shselasky USB_BUS_LOCK(&sc->sc_dci.sc_bus); 231187175Sthompsa at91_vbus_poll(sc); 232240314Shselasky USB_BUS_UNLOCK(&sc->sc_dci.sc_bus); 233184610Salfred } 234184610Salfred return (0); 235184610Salfred 236184610Salfrederror: 237184610Salfred at91_udp_detach(dev); 238184610Salfred return (ENXIO); 239184610Salfred} 240184610Salfred 241184610Salfredstatic int 242184610Salfredat91_udp_detach(device_t dev) 243184610Salfred{ 244184610Salfred struct at91_udp_softc *sc = device_get_softc(dev); 245184610Salfred device_t bdev; 246184610Salfred int err; 247184610Salfred 248184610Salfred if (sc->sc_dci.sc_bus.bdev) { 249184610Salfred bdev = sc->sc_dci.sc_bus.bdev; 250184610Salfred device_detach(bdev); 251184610Salfred device_delete_child(dev, bdev); 252184610Salfred } 253184610Salfred /* during module unload there are lots of children leftover */ 254227849Shselasky device_delete_children(dev); 255184610Salfred 256240314Shselasky USB_BUS_LOCK(&sc->sc_dci.sc_bus); 257240314Shselasky callout_stop(&sc->sc_vbus); 258240314Shselasky USB_BUS_UNLOCK(&sc->sc_dci.sc_bus); 259240314Shselasky 260240314Shselasky callout_drain(&sc->sc_vbus); 261240314Shselasky 262184610Salfred /* disable Transceiver */ 263184610Salfred AT91_UDP_WRITE_4(&sc->sc_dci, AT91_UDP_TXVC, AT91_UDP_TXVC_DIS); 264184610Salfred 265184610Salfred /* disable and clear all interrupts */ 266184610Salfred AT91_UDP_WRITE_4(&sc->sc_dci, AT91_UDP_IDR, 0xFFFFFFFF); 267184610Salfred AT91_UDP_WRITE_4(&sc->sc_dci, AT91_UDP_ICR, 0xFFFFFFFF); 268184610Salfred 269184610Salfred if (sc->sc_dci.sc_irq_res && sc->sc_dci.sc_intr_hdl) { 270184610Salfred /* 271184610Salfred * only call at91_udp_uninit() after at91_udp_init() 272184610Salfred */ 273184610Salfred at91dci_uninit(&sc->sc_dci); 274184610Salfred 275184610Salfred err = bus_teardown_intr(dev, sc->sc_dci.sc_irq_res, 276184610Salfred sc->sc_dci.sc_intr_hdl); 277184610Salfred sc->sc_dci.sc_intr_hdl = NULL; 278184610Salfred } 279184610Salfred if (sc->sc_dci.sc_irq_res) { 280184610Salfred bus_release_resource(dev, SYS_RES_IRQ, 0, 281184610Salfred sc->sc_dci.sc_irq_res); 282184610Salfred sc->sc_dci.sc_irq_res = NULL; 283184610Salfred } 284184610Salfred if (sc->sc_dci.sc_io_res) { 285184610Salfred bus_release_resource(dev, SYS_RES_MEMORY, MEM_RID, 286184610Salfred sc->sc_dci.sc_io_res); 287184610Salfred sc->sc_dci.sc_io_res = NULL; 288184610Salfred } 289194228Sthompsa usb_bus_mem_free_all(&sc->sc_dci.sc_bus, NULL); 290184610Salfred 291184610Salfred /* disable clocks */ 292184610Salfred at91_pmc_clock_disable(sc->sc_iclk); 293184610Salfred at91_pmc_clock_disable(sc->sc_fclk); 294239531Shselasky at91_pmc_clock_disable(sc->sc_mclk); 295184610Salfred at91_pmc_clock_deref(sc->sc_fclk); 296184610Salfred at91_pmc_clock_deref(sc->sc_iclk); 297239531Shselasky at91_pmc_clock_deref(sc->sc_mclk); 298184610Salfred 299184610Salfred return (0); 300184610Salfred} 301184610Salfred 302184610Salfredstatic device_method_t at91_udp_methods[] = { 303184610Salfred /* Device interface */ 304184610Salfred DEVMETHOD(device_probe, at91_udp_probe), 305184610Salfred DEVMETHOD(device_attach, at91_udp_attach), 306184610Salfred DEVMETHOD(device_detach, at91_udp_detach), 307228483Shselasky DEVMETHOD(device_suspend, bus_generic_suspend), 308228483Shselasky DEVMETHOD(device_resume, bus_generic_resume), 309228483Shselasky DEVMETHOD(device_shutdown, bus_generic_shutdown), 310184610Salfred 311227843Smarius DEVMETHOD_END 312184610Salfred}; 313184610Salfred 314184610Salfredstatic driver_t at91_udp_driver = { 315228483Shselasky .name = "at91_udp", 316228483Shselasky .methods = at91_udp_methods, 317228483Shselasky .size = sizeof(struct at91_udp_softc), 318184610Salfred}; 319184610Salfred 320184610Salfredstatic devclass_t at91_udp_devclass; 321184610Salfred 322184610SalfredDRIVER_MODULE(at91_udp, atmelarm, at91_udp_driver, at91_udp_devclass, 0, 0); 323