Esempio n. 1
0
static int
at91_udp_attach(device_t dev)
{
	struct at91_udp_softc *sc = device_get_softc(dev);
	int err;
	int rid;

	/* setup AT9100 USB device controller interface softc */

	sc->sc_dci.sc_clocks_on = &at91_udp_clocks_on;
	sc->sc_dci.sc_clocks_off = &at91_udp_clocks_off;
	sc->sc_dci.sc_clocks_arg = sc;
	sc->sc_dci.sc_pull_up = &at91_udp_pull_up;
	sc->sc_dci.sc_pull_down = &at91_udp_pull_down;
	sc->sc_dci.sc_pull_arg = sc;

	/* initialise some bus fields */
	sc->sc_dci.sc_bus.parent = dev;
	sc->sc_dci.sc_bus.devices = sc->sc_dci.sc_devices;
	sc->sc_dci.sc_bus.devices_max = AT91_MAX_DEVICES;

	/* get all DMA memory */
	if (usb_bus_mem_alloc_all(&sc->sc_dci.sc_bus,
	    USB_GET_DMA_TAG(dev), NULL)) {
		return (ENOMEM);
	}
	callout_init_mtx(&sc->sc_vbus, &sc->sc_dci.sc_bus.bus_mtx, 0);

	/*
	 * configure VBUS input pin, enable deglitch and enable
	 * interrupt :
	 */
	at91_pio_use_gpio(VBUS_BASE, VBUS_MASK);
	at91_pio_gpio_input(VBUS_BASE, VBUS_MASK);
	at91_pio_gpio_set_deglitch(VBUS_BASE, VBUS_MASK, 1);
	at91_pio_gpio_set_interrupt(VBUS_BASE, VBUS_MASK, 0);

	/*
	 * configure PULLUP output pin :
	 */
	at91_pio_use_gpio(PULLUP_BASE, PULLUP_MASK);
	at91_pio_gpio_output(PULLUP_BASE, PULLUP_MASK, 0);

	at91_udp_pull_down(sc);

	/* wait 10ms for pulldown to stabilise */
	usb_pause_mtx(NULL, hz / 100);

	sc->sc_mclk = at91_pmc_clock_ref("mck");
	sc->sc_iclk = at91_pmc_clock_ref("udc_clk");
	sc->sc_fclk = at91_pmc_clock_ref("udpck");

	rid = MEM_RID;
	sc->sc_dci.sc_io_res =
	    bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);

	if (!(sc->sc_dci.sc_io_res)) {
		err = ENOMEM;
		goto error;
	}
	sc->sc_dci.sc_io_tag = rman_get_bustag(sc->sc_dci.sc_io_res);
	sc->sc_dci.sc_io_hdl = rman_get_bushandle(sc->sc_dci.sc_io_res);
	sc->sc_dci.sc_io_size = rman_get_size(sc->sc_dci.sc_io_res);

	rid = 0;
	sc->sc_dci.sc_irq_res =
	    bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
	if (!(sc->sc_dci.sc_irq_res)) {
		goto error;
	}
	sc->sc_dci.sc_bus.bdev = device_add_child(dev, "usbus", -1);
	if (!(sc->sc_dci.sc_bus.bdev)) {
		goto error;
	}
	device_set_ivars(sc->sc_dci.sc_bus.bdev, &sc->sc_dci.sc_bus);

	err = bus_setup_intr(dev, sc->sc_dci.sc_irq_res, INTR_TYPE_TTY | INTR_MPSAFE,
	    at91dci_filter_interrupt, at91dci_interrupt, sc, &sc->sc_dci.sc_intr_hdl);
	if (err) {
		sc->sc_dci.sc_intr_hdl = NULL;
		goto error;
	}

	err = at91dci_init(&sc->sc_dci);
	if (!err) {
		err = device_probe_and_attach(sc->sc_dci.sc_bus.bdev);
	}
	if (err) {
		goto error;
	} else {
		/* poll VBUS one time */
		USB_BUS_LOCK(&sc->sc_dci.sc_bus);
		at91_vbus_poll(sc);
		USB_BUS_UNLOCK(&sc->sc_dci.sc_bus);
	}
	return (0);

error:
	at91_udp_detach(dev);
	return (ENXIO);
}
Esempio n. 2
0
static int
at91_udp_detach(device_t dev)
{
    struct at91_udp_softc *sc = device_get_softc(dev);
    device_t bdev;
    int err;

    if (sc->sc_dci.sc_bus.bdev) {
        bdev = sc->sc_dci.sc_bus.bdev;
        device_detach(bdev);
        device_delete_child(dev, bdev);
    }
    /* during module unload there are lots of children leftover */
    device_delete_all_children(dev);

    /* disable Transceiver */
    AT91_UDP_WRITE_4(&sc->sc_dci, AT91_UDP_TXVC, AT91_UDP_TXVC_DIS);

    /* disable and clear all interrupts */
    AT91_UDP_WRITE_4(&sc->sc_dci, AT91_UDP_IDR, 0xFFFFFFFF);
    AT91_UDP_WRITE_4(&sc->sc_dci, AT91_UDP_ICR, 0xFFFFFFFF);

    /* disable VBUS interrupt */
    at91_pio_gpio_set_interrupt(VBUS_BASE, VBUS_MASK, 0);

    if (sc->sc_vbus_irq_res && sc->sc_vbus_intr_hdl) {
        err = bus_teardown_intr(dev, sc->sc_vbus_irq_res,
                                sc->sc_vbus_intr_hdl);
        sc->sc_vbus_intr_hdl = NULL;
    }
    if (sc->sc_vbus_irq_res) {
        bus_release_resource(dev, SYS_RES_IRQ, 1,
                             sc->sc_vbus_irq_res);
        sc->sc_vbus_irq_res = NULL;
    }
    if (sc->sc_dci.sc_irq_res && sc->sc_dci.sc_intr_hdl) {
        /*
         * only call at91_udp_uninit() after at91_udp_init()
         */
        at91dci_uninit(&sc->sc_dci);

        err = bus_teardown_intr(dev, sc->sc_dci.sc_irq_res,
                                sc->sc_dci.sc_intr_hdl);
        sc->sc_dci.sc_intr_hdl = NULL;
    }
    if (sc->sc_dci.sc_irq_res) {
        bus_release_resource(dev, SYS_RES_IRQ, 0,
                             sc->sc_dci.sc_irq_res);
        sc->sc_dci.sc_irq_res = NULL;
    }
    if (sc->sc_dci.sc_io_res) {
        bus_release_resource(dev, SYS_RES_MEMORY, MEM_RID,
                             sc->sc_dci.sc_io_res);
        sc->sc_dci.sc_io_res = NULL;
    }
    usb_bus_mem_free_all(&sc->sc_dci.sc_bus, NULL);

    /* disable clocks */
    at91_pmc_clock_disable(sc->sc_iclk);
    at91_pmc_clock_disable(sc->sc_fclk);
    at91_pmc_clock_deref(sc->sc_fclk);
    at91_pmc_clock_deref(sc->sc_iclk);

    return (0);
}