1262601Simp#include <sys/cdefs.h> 2262601Simp__FBSDID("$FreeBSD: releng/11.0/sys/dev/usb/controller/at91dci_fdt.c 276717 2015-01-05 20:22:18Z hselasky $"); 3262601Simp 4262601Simp/*- 5262601Simp * Copyright (c) 2007-2008 Hans Petter Selasky. All rights reserved. 6262601Simp * 7262601Simp * Redistribution and use in source and binary forms, with or without 8262601Simp * modification, are permitted provided that the following conditions 9262601Simp * are met: 10262601Simp * 1. Redistributions of source code must retain the above copyright 11262601Simp * notice, this list of conditions and the following disclaimer. 12262601Simp * 2. Redistributions in binary form must reproduce the above copyright 13262601Simp * notice, this list of conditions and the following disclaimer in the 14262601Simp * documentation and/or other materials provided with the distribution. 15262601Simp * 16262601Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17262601Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18262601Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19262601Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20262601Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21262601Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22262601Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23262601Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24262601Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25262601Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26262601Simp * SUCH DAMAGE. 27262601Simp */ 28262601Simp 29262601Simp#include <sys/stdint.h> 30262601Simp#include <sys/stddef.h> 31262601Simp#include <sys/param.h> 32262601Simp#include <sys/queue.h> 33262601Simp#include <sys/types.h> 34262601Simp#include <sys/systm.h> 35262601Simp#include <sys/kernel.h> 36262601Simp#include <sys/bus.h> 37262601Simp#include <sys/module.h> 38262601Simp#include <sys/lock.h> 39262601Simp#include <sys/mutex.h> 40262601Simp#include <sys/condvar.h> 41262601Simp#include <sys/sysctl.h> 42262601Simp#include <sys/sx.h> 43262601Simp#include <sys/unistd.h> 44262601Simp#include <sys/callout.h> 45262601Simp#include <sys/malloc.h> 46262601Simp#include <sys/priv.h> 47262601Simp 48262601Simp#include <dev/usb/usb.h> 49262601Simp#include <dev/usb/usbdi.h> 50262601Simp 51262601Simp#include <dev/usb/usb_core.h> 52262601Simp#include <dev/usb/usb_busdma.h> 53262601Simp#include <dev/usb/usb_process.h> 54262601Simp#include <dev/usb/usb_util.h> 55262601Simp 56262601Simp#include <dev/usb/usb_controller.h> 57262601Simp#include <dev/usb/usb_bus.h> 58262601Simp#include <dev/usb/controller/at91dci.h> 59262601Simp 60262601Simp#include <sys/rman.h> 61262601Simp 62262601Simp#include <arm/at91/at91_pmcvar.h> 63262601Simp#include <arm/at91/at91rm92reg.h> 64262601Simp#include <arm/at91/at91_pioreg.h> 65262601Simp#include <arm/at91/at91_piovar.h> 66262601Simp 67262601Simp#include <dev/fdt/fdt_common.h> 68262601Simp#include <dev/ofw/ofw_bus.h> 69262601Simp#include <dev/ofw/ofw_bus_subr.h> 70262601Simp 71262601Simp#define MEM_RID 0 72262601Simp 73262601Simp/* Pin Definitions - do they belong here or somewhere else ? -- YES! */ 74262601Simp 75262601Simp#define VBUS_MASK AT91C_PIO_PB24 76262601Simp#define VBUS_BASE AT91RM92_PIOB_BASE 77262601Simp 78262601Simp#define PULLUP_MASK AT91C_PIO_PB22 79262601Simp#define PULLUP_BASE AT91RM92_PIOB_BASE 80262601Simp 81262601Simpstatic device_probe_t at91_udp_probe; 82262601Simpstatic device_attach_t at91_udp_attach; 83262601Simpstatic device_detach_t at91_udp_detach; 84262601Simp 85262601Simpstruct at91_udp_softc { 86262601Simp struct at91dci_softc sc_dci; /* must be first */ 87262601Simp struct at91_pmc_clock *sc_mclk; 88262601Simp struct at91_pmc_clock *sc_iclk; 89262601Simp struct at91_pmc_clock *sc_fclk; 90262601Simp struct callout sc_vbus; 91262601Simp}; 92262601Simp 93262601Simpstatic void 94262601Simpat91_vbus_poll(struct at91_udp_softc *sc) 95262601Simp{ 96262601Simp uint8_t vbus_val; 97262601Simp 98262601Simp vbus_val = at91_pio_gpio_get(VBUS_BASE, VBUS_MASK) != 0; 99262601Simp at91dci_vbus_interrupt(&sc->sc_dci, vbus_val); 100262601Simp 101262601Simp callout_reset(&sc->sc_vbus, hz, (void *)&at91_vbus_poll, sc); 102262601Simp} 103262601Simp 104262601Simpstatic void 105262601Simpat91_udp_clocks_on(void *arg) 106262601Simp{ 107262601Simp struct at91_udp_softc *sc = arg; 108262601Simp 109262601Simp at91_pmc_clock_enable(sc->sc_mclk); 110262601Simp at91_pmc_clock_enable(sc->sc_iclk); 111262601Simp at91_pmc_clock_enable(sc->sc_fclk); 112262601Simp} 113262601Simp 114262601Simpstatic void 115262601Simpat91_udp_clocks_off(void *arg) 116262601Simp{ 117262601Simp struct at91_udp_softc *sc = arg; 118262601Simp 119262601Simp at91_pmc_clock_disable(sc->sc_fclk); 120262601Simp at91_pmc_clock_disable(sc->sc_iclk); 121262601Simp at91_pmc_clock_disable(sc->sc_mclk); 122262601Simp} 123262601Simp 124262601Simpstatic void 125262601Simpat91_udp_pull_up(void *arg) 126262601Simp{ 127262601Simp at91_pio_gpio_set(PULLUP_BASE, PULLUP_MASK); 128262601Simp} 129262601Simp 130262601Simpstatic void 131262601Simpat91_udp_pull_down(void *arg) 132262601Simp{ 133262601Simp at91_pio_gpio_clear(PULLUP_BASE, PULLUP_MASK); 134262601Simp} 135262601Simp 136262601Simpstatic int 137262601Simpat91_udp_probe(device_t dev) 138262601Simp{ 139262601Simp if (!ofw_bus_is_compatible(dev, "atmel,at91rm9200-udc")) 140262601Simp return (ENXIO); 141262601Simp device_set_desc(dev, "AT91 integrated AT91_UDP controller"); 142262601Simp return (0); 143262601Simp} 144262601Simp 145262601Simpstatic int 146262601Simpat91_udp_attach(device_t dev) 147262601Simp{ 148262601Simp struct at91_udp_softc *sc = device_get_softc(dev); 149262601Simp int err; 150262601Simp int rid; 151262601Simp 152262601Simp /* setup AT9100 USB device controller interface softc */ 153262601Simp 154262601Simp sc->sc_dci.sc_clocks_on = &at91_udp_clocks_on; 155262601Simp sc->sc_dci.sc_clocks_off = &at91_udp_clocks_off; 156262601Simp sc->sc_dci.sc_clocks_arg = sc; 157262601Simp sc->sc_dci.sc_pull_up = &at91_udp_pull_up; 158262601Simp sc->sc_dci.sc_pull_down = &at91_udp_pull_down; 159262601Simp sc->sc_dci.sc_pull_arg = sc; 160262601Simp 161262601Simp /* initialise some bus fields */ 162262601Simp sc->sc_dci.sc_bus.parent = dev; 163262601Simp sc->sc_dci.sc_bus.devices = sc->sc_dci.sc_devices; 164262601Simp sc->sc_dci.sc_bus.devices_max = AT91_MAX_DEVICES; 165276717Shselasky sc->sc_dci.sc_bus.dma_bits = 32; 166262601Simp 167262601Simp /* get all DMA memory */ 168262601Simp if (usb_bus_mem_alloc_all(&sc->sc_dci.sc_bus, 169262601Simp USB_GET_DMA_TAG(dev), NULL)) { 170262601Simp return (ENOMEM); 171262601Simp } 172262601Simp callout_init_mtx(&sc->sc_vbus, &sc->sc_dci.sc_bus.bus_mtx, 0); 173262601Simp 174262601Simp /* 175262601Simp * configure VBUS input pin, enable deglitch and enable 176262601Simp * interrupt : 177262601Simp */ 178262601Simp at91_pio_use_gpio(VBUS_BASE, VBUS_MASK); 179262601Simp at91_pio_gpio_input(VBUS_BASE, VBUS_MASK); 180262601Simp at91_pio_gpio_set_deglitch(VBUS_BASE, VBUS_MASK, 1); 181262601Simp at91_pio_gpio_set_interrupt(VBUS_BASE, VBUS_MASK, 0); 182262601Simp 183262601Simp /* 184262601Simp * configure PULLUP output pin : 185262601Simp */ 186262601Simp at91_pio_use_gpio(PULLUP_BASE, PULLUP_MASK); 187262601Simp at91_pio_gpio_output(PULLUP_BASE, PULLUP_MASK, 0); 188262601Simp 189262601Simp at91_udp_pull_down(sc); 190262601Simp 191262601Simp /* wait 10ms for pulldown to stabilise */ 192262601Simp usb_pause_mtx(NULL, hz / 100); 193262601Simp 194262601Simp sc->sc_mclk = at91_pmc_clock_ref("mck"); 195262601Simp sc->sc_iclk = at91_pmc_clock_ref("udc_clk"); 196262601Simp sc->sc_fclk = at91_pmc_clock_ref("udpck"); 197262601Simp 198262601Simp rid = MEM_RID; 199262601Simp sc->sc_dci.sc_io_res = 200262601Simp bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 201262601Simp 202262601Simp if (!(sc->sc_dci.sc_io_res)) { 203262601Simp err = ENOMEM; 204262601Simp goto error; 205262601Simp } 206262601Simp sc->sc_dci.sc_io_tag = rman_get_bustag(sc->sc_dci.sc_io_res); 207262601Simp sc->sc_dci.sc_io_hdl = rman_get_bushandle(sc->sc_dci.sc_io_res); 208262601Simp sc->sc_dci.sc_io_size = rman_get_size(sc->sc_dci.sc_io_res); 209262601Simp 210262601Simp rid = 0; 211262601Simp sc->sc_dci.sc_irq_res = 212262601Simp bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); 213262601Simp if (!(sc->sc_dci.sc_irq_res)) { 214262601Simp goto error; 215262601Simp } 216262601Simp sc->sc_dci.sc_bus.bdev = device_add_child(dev, "usbus", -1); 217262601Simp if (!(sc->sc_dci.sc_bus.bdev)) { 218262601Simp goto error; 219262601Simp } 220262601Simp device_set_ivars(sc->sc_dci.sc_bus.bdev, &sc->sc_dci.sc_bus); 221262601Simp 222269604Shselasky err = bus_setup_intr(dev, sc->sc_dci.sc_irq_res, INTR_TYPE_TTY | INTR_MPSAFE, 223269604Shselasky at91dci_filter_interrupt, at91dci_interrupt, sc, &sc->sc_dci.sc_intr_hdl); 224262601Simp if (err) { 225262601Simp sc->sc_dci.sc_intr_hdl = NULL; 226262601Simp goto error; 227262601Simp } 228262601Simp 229262601Simp err = at91dci_init(&sc->sc_dci); 230262601Simp if (!err) { 231262601Simp err = device_probe_and_attach(sc->sc_dci.sc_bus.bdev); 232262601Simp } 233262601Simp if (err) { 234262601Simp goto error; 235262601Simp } else { 236262601Simp /* poll VBUS one time */ 237262601Simp USB_BUS_LOCK(&sc->sc_dci.sc_bus); 238262601Simp at91_vbus_poll(sc); 239262601Simp USB_BUS_UNLOCK(&sc->sc_dci.sc_bus); 240262601Simp } 241262601Simp return (0); 242262601Simp 243262601Simperror: 244262601Simp at91_udp_detach(dev); 245262601Simp return (ENXIO); 246262601Simp} 247262601Simp 248262601Simpstatic int 249262601Simpat91_udp_detach(device_t dev) 250262601Simp{ 251262601Simp struct at91_udp_softc *sc = device_get_softc(dev); 252262601Simp device_t bdev; 253262601Simp int err; 254262601Simp 255262601Simp if (sc->sc_dci.sc_bus.bdev) { 256262601Simp bdev = sc->sc_dci.sc_bus.bdev; 257262601Simp device_detach(bdev); 258262601Simp device_delete_child(dev, bdev); 259262601Simp } 260262601Simp /* during module unload there are lots of children leftover */ 261262601Simp device_delete_children(dev); 262262601Simp 263262601Simp USB_BUS_LOCK(&sc->sc_dci.sc_bus); 264262601Simp callout_stop(&sc->sc_vbus); 265262601Simp USB_BUS_UNLOCK(&sc->sc_dci.sc_bus); 266262601Simp 267262601Simp callout_drain(&sc->sc_vbus); 268262601Simp 269262601Simp /* disable Transceiver */ 270262601Simp AT91_UDP_WRITE_4(&sc->sc_dci, AT91_UDP_TXVC, AT91_UDP_TXVC_DIS); 271262601Simp 272262601Simp /* disable and clear all interrupts */ 273262601Simp AT91_UDP_WRITE_4(&sc->sc_dci, AT91_UDP_IDR, 0xFFFFFFFF); 274262601Simp AT91_UDP_WRITE_4(&sc->sc_dci, AT91_UDP_ICR, 0xFFFFFFFF); 275262601Simp 276262601Simp if (sc->sc_dci.sc_irq_res && sc->sc_dci.sc_intr_hdl) { 277262601Simp /* 278262601Simp * only call at91_udp_uninit() after at91_udp_init() 279262601Simp */ 280262601Simp at91dci_uninit(&sc->sc_dci); 281262601Simp 282262601Simp err = bus_teardown_intr(dev, sc->sc_dci.sc_irq_res, 283262601Simp sc->sc_dci.sc_intr_hdl); 284262601Simp sc->sc_dci.sc_intr_hdl = NULL; 285262601Simp } 286262601Simp if (sc->sc_dci.sc_irq_res) { 287262601Simp bus_release_resource(dev, SYS_RES_IRQ, 0, 288262601Simp sc->sc_dci.sc_irq_res); 289262601Simp sc->sc_dci.sc_irq_res = NULL; 290262601Simp } 291262601Simp if (sc->sc_dci.sc_io_res) { 292262601Simp bus_release_resource(dev, SYS_RES_MEMORY, MEM_RID, 293262601Simp sc->sc_dci.sc_io_res); 294262601Simp sc->sc_dci.sc_io_res = NULL; 295262601Simp } 296262601Simp usb_bus_mem_free_all(&sc->sc_dci.sc_bus, NULL); 297262601Simp 298262601Simp /* disable clocks */ 299262601Simp at91_pmc_clock_disable(sc->sc_iclk); 300262601Simp at91_pmc_clock_disable(sc->sc_fclk); 301262601Simp at91_pmc_clock_disable(sc->sc_mclk); 302262601Simp at91_pmc_clock_deref(sc->sc_fclk); 303262601Simp at91_pmc_clock_deref(sc->sc_iclk); 304262601Simp at91_pmc_clock_deref(sc->sc_mclk); 305262601Simp 306262601Simp return (0); 307262601Simp} 308262601Simp 309262601Simpstatic device_method_t at91_udp_methods[] = { 310262601Simp /* Device interface */ 311262601Simp DEVMETHOD(device_probe, at91_udp_probe), 312262601Simp DEVMETHOD(device_attach, at91_udp_attach), 313262601Simp DEVMETHOD(device_detach, at91_udp_detach), 314262601Simp DEVMETHOD(device_suspend, bus_generic_suspend), 315262601Simp DEVMETHOD(device_resume, bus_generic_resume), 316262601Simp DEVMETHOD(device_shutdown, bus_generic_shutdown), 317262601Simp 318262601Simp DEVMETHOD_END 319262601Simp}; 320262601Simp 321262601Simpstatic driver_t at91_udp_driver = { 322262601Simp .name = "at91_udp", 323262601Simp .methods = at91_udp_methods, 324262601Simp .size = sizeof(struct at91_udp_softc), 325262601Simp}; 326262601Simp 327262601Simpstatic devclass_t at91_udp_devclass; 328262601Simp 329262601SimpDRIVER_MODULE(at91_udp, simplebus, at91_udp_driver, at91_udp_devclass, 0, 0); 330