at91dci_fdt.c revision 330897
1#include <sys/cdefs.h> 2__FBSDID("$FreeBSD: stable/11/sys/dev/usb/controller/at91dci_fdt.c 330897 2018-03-14 03:19:51Z eadler $"); 3 4/*- 5 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 6 * 7 * Copyright (c) 2007-2008 Hans Petter Selasky. All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31#include <sys/stdint.h> 32#include <sys/stddef.h> 33#include <sys/param.h> 34#include <sys/queue.h> 35#include <sys/types.h> 36#include <sys/systm.h> 37#include <sys/kernel.h> 38#include <sys/bus.h> 39#include <sys/module.h> 40#include <sys/lock.h> 41#include <sys/mutex.h> 42#include <sys/condvar.h> 43#include <sys/sysctl.h> 44#include <sys/sx.h> 45#include <sys/unistd.h> 46#include <sys/callout.h> 47#include <sys/malloc.h> 48#include <sys/priv.h> 49 50#include <dev/usb/usb.h> 51#include <dev/usb/usbdi.h> 52 53#include <dev/usb/usb_core.h> 54#include <dev/usb/usb_busdma.h> 55#include <dev/usb/usb_process.h> 56#include <dev/usb/usb_util.h> 57 58#include <dev/usb/usb_controller.h> 59#include <dev/usb/usb_bus.h> 60#include <dev/usb/controller/at91dci.h> 61 62#include <sys/rman.h> 63 64#include <arm/at91/at91_pmcvar.h> 65#include <arm/at91/at91rm92reg.h> 66#include <arm/at91/at91_pioreg.h> 67#include <arm/at91/at91_piovar.h> 68 69#include <dev/fdt/fdt_common.h> 70#include <dev/ofw/ofw_bus.h> 71#include <dev/ofw/ofw_bus_subr.h> 72 73#define MEM_RID 0 74 75/* Pin Definitions - do they belong here or somewhere else ? -- YES! */ 76 77#define VBUS_MASK AT91C_PIO_PB24 78#define VBUS_BASE AT91RM92_PIOB_BASE 79 80#define PULLUP_MASK AT91C_PIO_PB22 81#define PULLUP_BASE AT91RM92_PIOB_BASE 82 83static device_probe_t at91_udp_probe; 84static device_attach_t at91_udp_attach; 85static device_detach_t at91_udp_detach; 86 87struct at91_udp_softc { 88 struct at91dci_softc sc_dci; /* must be first */ 89 struct at91_pmc_clock *sc_mclk; 90 struct at91_pmc_clock *sc_iclk; 91 struct at91_pmc_clock *sc_fclk; 92 struct callout sc_vbus; 93}; 94 95static void 96at91_vbus_poll(struct at91_udp_softc *sc) 97{ 98 uint8_t vbus_val; 99 100 vbus_val = at91_pio_gpio_get(VBUS_BASE, VBUS_MASK) != 0; 101 at91dci_vbus_interrupt(&sc->sc_dci, vbus_val); 102 103 callout_reset(&sc->sc_vbus, hz, (void *)&at91_vbus_poll, sc); 104} 105 106static void 107at91_udp_clocks_on(void *arg) 108{ 109 struct at91_udp_softc *sc = arg; 110 111 at91_pmc_clock_enable(sc->sc_mclk); 112 at91_pmc_clock_enable(sc->sc_iclk); 113 at91_pmc_clock_enable(sc->sc_fclk); 114} 115 116static void 117at91_udp_clocks_off(void *arg) 118{ 119 struct at91_udp_softc *sc = arg; 120 121 at91_pmc_clock_disable(sc->sc_fclk); 122 at91_pmc_clock_disable(sc->sc_iclk); 123 at91_pmc_clock_disable(sc->sc_mclk); 124} 125 126static void 127at91_udp_pull_up(void *arg) 128{ 129 at91_pio_gpio_set(PULLUP_BASE, PULLUP_MASK); 130} 131 132static void 133at91_udp_pull_down(void *arg) 134{ 135 at91_pio_gpio_clear(PULLUP_BASE, PULLUP_MASK); 136} 137 138static int 139at91_udp_probe(device_t dev) 140{ 141 if (!ofw_bus_is_compatible(dev, "atmel,at91rm9200-udc")) 142 return (ENXIO); 143 device_set_desc(dev, "AT91 integrated AT91_UDP controller"); 144 return (0); 145} 146 147static int 148at91_udp_attach(device_t dev) 149{ 150 struct at91_udp_softc *sc = device_get_softc(dev); 151 int err; 152 int rid; 153 154 /* setup AT9100 USB device controller interface softc */ 155 156 sc->sc_dci.sc_clocks_on = &at91_udp_clocks_on; 157 sc->sc_dci.sc_clocks_off = &at91_udp_clocks_off; 158 sc->sc_dci.sc_clocks_arg = sc; 159 sc->sc_dci.sc_pull_up = &at91_udp_pull_up; 160 sc->sc_dci.sc_pull_down = &at91_udp_pull_down; 161 sc->sc_dci.sc_pull_arg = sc; 162 163 /* initialise some bus fields */ 164 sc->sc_dci.sc_bus.parent = dev; 165 sc->sc_dci.sc_bus.devices = sc->sc_dci.sc_devices; 166 sc->sc_dci.sc_bus.devices_max = AT91_MAX_DEVICES; 167 sc->sc_dci.sc_bus.dma_bits = 32; 168 169 /* get all DMA memory */ 170 if (usb_bus_mem_alloc_all(&sc->sc_dci.sc_bus, 171 USB_GET_DMA_TAG(dev), NULL)) { 172 return (ENOMEM); 173 } 174 callout_init_mtx(&sc->sc_vbus, &sc->sc_dci.sc_bus.bus_mtx, 0); 175 176 /* 177 * configure VBUS input pin, enable deglitch and enable 178 * interrupt : 179 */ 180 at91_pio_use_gpio(VBUS_BASE, VBUS_MASK); 181 at91_pio_gpio_input(VBUS_BASE, VBUS_MASK); 182 at91_pio_gpio_set_deglitch(VBUS_BASE, VBUS_MASK, 1); 183 at91_pio_gpio_set_interrupt(VBUS_BASE, VBUS_MASK, 0); 184 185 /* 186 * configure PULLUP output pin : 187 */ 188 at91_pio_use_gpio(PULLUP_BASE, PULLUP_MASK); 189 at91_pio_gpio_output(PULLUP_BASE, PULLUP_MASK, 0); 190 191 at91_udp_pull_down(sc); 192 193 /* wait 10ms for pulldown to stabilise */ 194 usb_pause_mtx(NULL, hz / 100); 195 196 sc->sc_mclk = at91_pmc_clock_ref("mck"); 197 sc->sc_iclk = at91_pmc_clock_ref("udc_clk"); 198 sc->sc_fclk = at91_pmc_clock_ref("udpck"); 199 200 rid = MEM_RID; 201 sc->sc_dci.sc_io_res = 202 bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 203 204 if (!(sc->sc_dci.sc_io_res)) { 205 err = ENOMEM; 206 goto error; 207 } 208 sc->sc_dci.sc_io_tag = rman_get_bustag(sc->sc_dci.sc_io_res); 209 sc->sc_dci.sc_io_hdl = rman_get_bushandle(sc->sc_dci.sc_io_res); 210 sc->sc_dci.sc_io_size = rman_get_size(sc->sc_dci.sc_io_res); 211 212 rid = 0; 213 sc->sc_dci.sc_irq_res = 214 bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); 215 if (!(sc->sc_dci.sc_irq_res)) { 216 goto error; 217 } 218 sc->sc_dci.sc_bus.bdev = device_add_child(dev, "usbus", -1); 219 if (!(sc->sc_dci.sc_bus.bdev)) { 220 goto error; 221 } 222 device_set_ivars(sc->sc_dci.sc_bus.bdev, &sc->sc_dci.sc_bus); 223 224 err = bus_setup_intr(dev, sc->sc_dci.sc_irq_res, INTR_TYPE_TTY | INTR_MPSAFE, 225 at91dci_filter_interrupt, at91dci_interrupt, sc, &sc->sc_dci.sc_intr_hdl); 226 if (err) { 227 sc->sc_dci.sc_intr_hdl = NULL; 228 goto error; 229 } 230 231 err = at91dci_init(&sc->sc_dci); 232 if (!err) { 233 err = device_probe_and_attach(sc->sc_dci.sc_bus.bdev); 234 } 235 if (err) { 236 goto error; 237 } else { 238 /* poll VBUS one time */ 239 USB_BUS_LOCK(&sc->sc_dci.sc_bus); 240 at91_vbus_poll(sc); 241 USB_BUS_UNLOCK(&sc->sc_dci.sc_bus); 242 } 243 return (0); 244 245error: 246 at91_udp_detach(dev); 247 return (ENXIO); 248} 249 250static int 251at91_udp_detach(device_t dev) 252{ 253 struct at91_udp_softc *sc = device_get_softc(dev); 254 int err; 255 256 /* during module unload there are lots of children leftover */ 257 device_delete_children(dev); 258 259 USB_BUS_LOCK(&sc->sc_dci.sc_bus); 260 callout_stop(&sc->sc_vbus); 261 USB_BUS_UNLOCK(&sc->sc_dci.sc_bus); 262 263 callout_drain(&sc->sc_vbus); 264 265 /* disable Transceiver */ 266 AT91_UDP_WRITE_4(&sc->sc_dci, AT91_UDP_TXVC, AT91_UDP_TXVC_DIS); 267 268 /* disable and clear all interrupts */ 269 AT91_UDP_WRITE_4(&sc->sc_dci, AT91_UDP_IDR, 0xFFFFFFFF); 270 AT91_UDP_WRITE_4(&sc->sc_dci, AT91_UDP_ICR, 0xFFFFFFFF); 271 272 if (sc->sc_dci.sc_irq_res && sc->sc_dci.sc_intr_hdl) { 273 /* 274 * only call at91_udp_uninit() after at91_udp_init() 275 */ 276 at91dci_uninit(&sc->sc_dci); 277 278 err = bus_teardown_intr(dev, sc->sc_dci.sc_irq_res, 279 sc->sc_dci.sc_intr_hdl); 280 sc->sc_dci.sc_intr_hdl = NULL; 281 } 282 if (sc->sc_dci.sc_irq_res) { 283 bus_release_resource(dev, SYS_RES_IRQ, 0, 284 sc->sc_dci.sc_irq_res); 285 sc->sc_dci.sc_irq_res = NULL; 286 } 287 if (sc->sc_dci.sc_io_res) { 288 bus_release_resource(dev, SYS_RES_MEMORY, MEM_RID, 289 sc->sc_dci.sc_io_res); 290 sc->sc_dci.sc_io_res = NULL; 291 } 292 usb_bus_mem_free_all(&sc->sc_dci.sc_bus, NULL); 293 294 /* disable clocks */ 295 at91_pmc_clock_disable(sc->sc_iclk); 296 at91_pmc_clock_disable(sc->sc_fclk); 297 at91_pmc_clock_disable(sc->sc_mclk); 298 at91_pmc_clock_deref(sc->sc_fclk); 299 at91_pmc_clock_deref(sc->sc_iclk); 300 at91_pmc_clock_deref(sc->sc_mclk); 301 302 return (0); 303} 304 305static device_method_t at91_udp_methods[] = { 306 /* Device interface */ 307 DEVMETHOD(device_probe, at91_udp_probe), 308 DEVMETHOD(device_attach, at91_udp_attach), 309 DEVMETHOD(device_detach, at91_udp_detach), 310 DEVMETHOD(device_suspend, bus_generic_suspend), 311 DEVMETHOD(device_resume, bus_generic_resume), 312 DEVMETHOD(device_shutdown, bus_generic_shutdown), 313 314 DEVMETHOD_END 315}; 316 317static driver_t at91_udp_driver = { 318 .name = "at91_udp", 319 .methods = at91_udp_methods, 320 .size = sizeof(struct at91_udp_softc), 321}; 322 323static devclass_t at91_udp_devclass; 324 325DRIVER_MODULE(at91_udp, simplebus, at91_udp_driver, at91_udp_devclass, 0, 0); 326