The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/mips/ingenic/jz4780_ehci.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2015 Oleksandr Tymoshenko <gonzo@freebsd.org>.
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   24  */
   25 
   26 /*
   27  * JZ4780 attachment driver for the USB Enhanced Host Controller.
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD$");
   32 
   33 #include "opt_bus.h"
   34 
   35 #include <sys/param.h>
   36 #include <sys/systm.h>
   37 #include <sys/bus.h>
   38 #include <sys/rman.h>
   39 #include <sys/condvar.h>
   40 #include <sys/kernel.h>
   41 #include <sys/module.h>
   42 #include <sys/gpio.h>
   43 
   44 #include <dev/extres/clk/clk.h>
   45 
   46 #include <dev/usb/usb.h>
   47 #include <dev/usb/usbdi.h>
   48 
   49 #include <dev/usb/usb_core.h>
   50 #include <dev/usb/usb_busdma.h>
   51 #include <dev/usb/usb_process.h>
   52 #include <dev/usb/usb_util.h>
   53 
   54 #include <dev/usb/usb_controller.h>
   55 #include <dev/usb/usb_bus.h>
   56 #include <dev/usb/controller/ehci.h>
   57 #include <dev/usb/controller/ehcireg.h>
   58 
   59 #include <dev/ofw/ofw_bus.h>
   60 #include <dev/ofw/ofw_bus_subr.h>
   61 
   62 #include <dev/gpio/gpiobusvar.h>
   63 
   64 #include <mips/ingenic/jz4780_clock.h>
   65 #include <mips/ingenic/jz4780_regs.h>
   66 
   67 #define EHCI_HC_DEVSTR          "Ingenic JZ4780 EHCI"
   68 
   69 struct jz4780_ehci_softc {
   70         ehci_softc_t            base;   /* storage for EHCI code */
   71         clk_t                   clk;
   72         struct gpiobus_pin *gpio_vbus;
   73 };
   74 
   75 static device_probe_t jz4780_ehci_probe;
   76 static device_attach_t jz4780_ehci_attach;
   77 static device_detach_t jz4780_ehci_detach;
   78 
   79 static int
   80 jz4780_ehci_vbus_gpio_enable(device_t dev)
   81 {
   82         struct gpiobus_pin *gpio_vbus;
   83         struct jz4780_ehci_softc *sc;
   84         int err;
   85 
   86         sc = device_get_softc(dev);
   87 
   88         err = ofw_gpiobus_parse_gpios(dev, "ingenic,vbus-gpio", &gpio_vbus);
   89         /*
   90          * The pin can ne already mapped by other device. Optimistically
   91          * surge ahead.
   92          */
   93         if (err <= 0)
   94                 return (0);
   95 
   96         sc->gpio_vbus = gpio_vbus;
   97         if (err > 1) {
   98                 device_printf(dev, "too many vbus gpios\n");
   99                 return (ENXIO);
  100         }
  101 
  102         if (sc->gpio_vbus != NULL) {
  103                 err = GPIO_PIN_SETFLAGS(sc->gpio_vbus->dev, sc->gpio_vbus->pin,
  104                     GPIO_PIN_OUTPUT);
  105                 if (err != 0) {
  106                         device_printf(dev, "Cannot configure GPIO pin %d on %s\n",
  107                             sc->gpio_vbus->pin, device_get_nameunit(sc->gpio_vbus->dev));
  108                         return (err);
  109                 }
  110 
  111                 err = GPIO_PIN_SET(sc->gpio_vbus->dev, sc->gpio_vbus->pin, 1);
  112                 if (err != 0) {
  113                         device_printf(dev, "Cannot configure GPIO pin %d on %s\n",
  114                             sc->gpio_vbus->pin, device_get_nameunit(sc->gpio_vbus->dev));
  115                         return (err);
  116                 }
  117         }
  118         return (0);
  119 }
  120 
  121 static int
  122 jz4780_ehci_clk_enable(device_t dev)
  123 {
  124         struct jz4780_ehci_softc *sc;
  125         int err;
  126 
  127         sc = device_get_softc(dev);
  128 
  129         err = clk_get_by_ofw_index(dev, 0, 0, &sc->clk);
  130         if (err != 0) {
  131                 device_printf(dev, "unable to lookup device clock\n");
  132                 return (err);
  133         }
  134         err = clk_enable(sc->clk);
  135         if (err != 0) {
  136                 device_printf(dev, "unable to enable device clock\n");
  137                 return (err);
  138         }
  139         err = clk_set_freq(sc->clk, 48000000, 0);
  140         if (err != 0) {
  141                 device_printf(dev, "unable to set device clock to 48 kHZ\n");
  142                 return (err);
  143         }
  144         return (0);
  145 }
  146 
  147 static void
  148 jz4780_ehci_intr(void *arg)
  149 {
  150 
  151         ehci_interrupt(arg);
  152 }
  153 
  154 static int
  155 jz4780_ehci_probe(device_t dev)
  156 {
  157 
  158         if (!ofw_bus_status_okay(dev))
  159                 return (ENXIO);
  160 
  161         if (!ofw_bus_is_compatible(dev, "ingenic,jz4780-ehci"))
  162                 return (ENXIO);
  163 
  164         device_set_desc(dev, EHCI_HC_DEVSTR);
  165 
  166         return (BUS_PROBE_DEFAULT);
  167 }
  168 
  169 static int
  170 jz4780_ehci_attach(device_t dev)
  171 {
  172         struct jz4780_ehci_softc *isc;
  173         ehci_softc_t *sc;
  174         int err;
  175         int rid;
  176         uint32_t reg;
  177 
  178         isc = device_get_softc(dev);
  179         sc = &isc->base;
  180 
  181         /* initialise some bus fields */
  182         sc->sc_bus.parent = dev;
  183         sc->sc_bus.devices = sc->sc_devices;
  184         sc->sc_bus.devices_max = EHCI_MAX_DEVICES;
  185         sc->sc_bus.dma_bits = 32;
  186 
  187         /* get all DMA memory */
  188         if (usb_bus_mem_alloc_all(&sc->sc_bus,
  189             USB_GET_DMA_TAG(dev), &ehci_iterate_hw_softc)) {
  190                 return (ENOMEM);
  191         }
  192 
  193         sc->sc_bus.usbrev = USB_REV_2_0;
  194 
  195         err = jz4780_ehci_vbus_gpio_enable(dev);
  196         if (err)
  197                 goto error;
  198 
  199         rid = 0;
  200         sc->sc_io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
  201         if (!sc->sc_io_res) {
  202                 device_printf(dev, "Could not map memory\n");
  203                 goto error;
  204         }
  205 
  206         /*
  207          * Craft special resource for bus space ops that handle
  208          * byte-alignment of non-word addresses.
  209          */
  210         sc->sc_io_tag = rman_get_bustag(sc->sc_io_res);
  211         sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res);
  212         sc->sc_io_size = rman_get_size(sc->sc_io_res);
  213 
  214         err = jz4780_ehci_clk_enable(dev);
  215         if (err)
  216                 goto error;
  217 
  218         if (jz4780_ehci_enable() != 0) {
  219                 device_printf(dev, "CGU failed to enable EHCI\n");
  220                 err = ENXIO;
  221                 goto error;
  222         }
  223 
  224         EWRITE4(sc, EHCI_USBINTR, 0);
  225 
  226         rid = 0;
  227         sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
  228             RF_ACTIVE | RF_SHAREABLE);
  229         if (sc->sc_irq_res == NULL) {
  230                 device_printf(dev, "Could not allocate irq\n");
  231                 goto error;
  232         }
  233         sc->sc_bus.bdev = device_add_child(dev, "usbus", -1);
  234         if (!sc->sc_bus.bdev) {
  235                 device_printf(dev, "Could not add USB device\n");
  236                 goto error;
  237         }
  238         device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus);
  239         device_set_desc(sc->sc_bus.bdev, EHCI_HC_DEVSTR);
  240 
  241         sprintf(sc->sc_vendor, "Ingenic");
  242 
  243         err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
  244             NULL, jz4780_ehci_intr, sc, &sc->sc_intr_hdl);
  245         if (err) {
  246                 device_printf(dev, "Could not setup irq, %d\n", err);
  247                 sc->sc_intr_hdl = NULL;
  248                 goto error;
  249         }
  250 
  251         err = ehci_init(sc);
  252         if (!err) {
  253                 /* Voodoo: set utmi data bus width on controller to 16 bit */
  254                 reg = EREAD4(sc, JZ_EHCI_REG_UTMI_BUS);
  255                 reg |= UTMI_BUS_WIDTH;
  256                 EWRITE4(sc, JZ_EHCI_REG_UTMI_BUS, reg);
  257 
  258                 err = device_probe_and_attach(sc->sc_bus.bdev);
  259         }
  260         if (err) {
  261                 device_printf(dev, "USB init failed err=%d\n", err);
  262                 goto error;
  263         }
  264         return (0);
  265 
  266 error:
  267         jz4780_ehci_detach(dev);
  268         return (ENXIO);
  269 }
  270 
  271 static int
  272 jz4780_ehci_detach(device_t dev)
  273 {
  274         struct jz4780_ehci_softc *isc;
  275         ehci_softc_t *sc;
  276         device_t bdev;
  277         int err;
  278 
  279         isc = device_get_softc(dev);
  280         sc = &isc->base;
  281 
  282         if (sc->sc_bus.bdev) {
  283                 bdev = sc->sc_bus.bdev;
  284                 device_detach(bdev);
  285                 device_delete_child(dev, bdev);
  286         }
  287         /* during module unload there are lots of children leftover */
  288         device_delete_children(dev);
  289 
  290         if (sc->sc_irq_res && sc->sc_intr_hdl) {
  291                 /*
  292                  * only call ehci_detach() after ehci_init()
  293                  */
  294                 ehci_detach(sc);
  295 
  296                 err = bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intr_hdl);
  297 
  298                 if (err)
  299                         /* XXX or should we panic? */
  300                         device_printf(dev, "Could not tear down irq, %d\n",
  301                             err);
  302                 sc->sc_intr_hdl = NULL;
  303         }
  304 
  305         if (sc->sc_irq_res) {
  306                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res);
  307                 sc->sc_irq_res = NULL;
  308         }
  309         if (sc->sc_io_res) {
  310                 bus_release_resource(dev, SYS_RES_MEMORY, 0,
  311                     sc->sc_io_res);
  312                 sc->sc_io_res = NULL;
  313         }
  314 
  315         if (isc->clk)
  316                 clk_release(isc->clk);
  317 
  318         usb_bus_mem_free_all(&sc->sc_bus, &ehci_iterate_hw_softc);
  319         free(isc->gpio_vbus, M_DEVBUF);
  320         return (0);
  321 }
  322 
  323 static device_method_t ehci_methods[] = {
  324         /* Device interface */
  325         DEVMETHOD(device_probe, jz4780_ehci_probe),
  326         DEVMETHOD(device_attach, jz4780_ehci_attach),
  327         DEVMETHOD(device_detach, jz4780_ehci_detach),
  328         DEVMETHOD(device_suspend, bus_generic_suspend),
  329         DEVMETHOD(device_resume, bus_generic_resume),
  330         DEVMETHOD(device_shutdown, bus_generic_shutdown),
  331 
  332         DEVMETHOD_END
  333 };
  334 
  335 static driver_t ehci_driver = {
  336         .name = "ehci",
  337         .methods = ehci_methods,
  338         .size = sizeof(struct jz4780_ehci_softc),
  339 };
  340 
  341 static devclass_t ehci_devclass;
  342 
  343 DRIVER_MODULE(ehci, simplebus, ehci_driver, ehci_devclass, 0, 0);
  344 MODULE_DEPEND(ehci, usb, 1, 1, 1);
  345 MODULE_DEPEND(ehci, gpio, 1, 1, 1);

Cache object: 682ede8155079298428bf1e6099edf83


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.