static int phy_init(struct vybrid_ehci_softc *esc) { device_t sc_gpio_dev; int reg; /* Reset phy */ reg = PHY_READ4(esc, USBPHY_CTRL); reg |= (USBPHY_CTRL_SFTRST); PHY_WRITE4(esc, USBPHY_CTRL, reg); /* Minimum reset time */ DELAY(10000); reg &= ~(USBPHY_CTRL_SFTRST | USBPHY_CTRL_CLKGATE); PHY_WRITE4(esc, USBPHY_CTRL, reg); reg = (ENUTMILEVEL2 | ENUTMILEVEL3); PHY_WRITE4(esc, USBPHY_CTRL_SET, reg); /* Get the GPIO device, we need this to give power to USB */ sc_gpio_dev = devclass_get_device(devclass_find("gpio"), 0); if (sc_gpio_dev == NULL) { device_printf(esc->dev, "Error: failed to get the GPIO dev\n"); return (1); } /* Give power to USB */ GPIO_PIN_SETFLAGS(sc_gpio_dev, GPIO_USB_PWR, GPIO_PIN_OUTPUT); GPIO_PIN_SET(sc_gpio_dev, GPIO_USB_PWR, GPIO_PIN_HIGH); /* Power up PHY */ PHY_WRITE4(esc, USBPHY_PWD, 0x00); /* Ungate clocks */ reg = PHY_READ4(esc, USBPHY_DEBUG); reg &= ~(USBPHY_DEBUG_CLKGATE); PHY_WRITE4(esc, USBPHY_DEBUG, reg); #if 0 printf("USBPHY_CTRL == 0x%08x\n", PHY_READ4(esc, USBPHY_CTRL)); printf("USBPHY_IP == 0x%08x\n", PHY_READ4(esc, USBPHY_IP)); printf("USBPHY_STATUS == 0x%08x\n", PHY_READ4(esc, USBPHY_STATUS)); printf("USBPHY_DEBUG == 0x%08x\n", PHY_READ4(esc, USBPHY_DEBUG)); printf("USBPHY_DEBUG0_STATUS == 0x%08x\n", PHY_READ4(esc, USBPHY_DEBUG0_STATUS)); printf("USBPHY_DEBUG1 == 0x%08x\n", PHY_READ4(esc, USBPHY_DEBUG1)); #endif return (0); }
int gpio_pin_setflags(gpio_pin_t pin, uint32_t flags) { int rv; KASSERT(pin != NULL, ("GPIO pin is NULL.")); KASSERT(pin->dev != NULL, ("GPIO pin device is NULL.")); rv = GPIO_PIN_SETFLAGS(pin->dev, pin->pin, flags); return (rv); }
static int gpiobus_pin_setflags(device_t dev, device_t child, uint32_t pin, uint32_t flags) { struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev); struct gpiobus_ivar *devi = GPIOBUS_IVAR(child); if (pin >= devi->npins) return (EINVAL); return GPIO_PIN_SETFLAGS(sc->sc_dev, devi->pins[pin], flags); }
static int gpio_ctrl(struct exynos_ehci_softc *esc, int dir, int power) { device_t gpio_dev; /* Get the GPIO device, we need this to give power to USB */ gpio_dev = devclass_get_device(devclass_find("gpio"), 0); if (gpio_dev == NULL) { device_printf(esc->dev, "cant find gpio_dev\n"); return (1); } if (power) GPIO_PIN_SET(gpio_dev, PIN_USB, GPIO_PIN_HIGH); else GPIO_PIN_SET(gpio_dev, PIN_USB, GPIO_PIN_LOW); if (dir) GPIO_PIN_SETFLAGS(gpio_dev, PIN_USB, GPIO_PIN_OUTPUT); else GPIO_PIN_SETFLAGS(gpio_dev, PIN_USB, GPIO_PIN_INPUT); return (0); }
static int gpiobus_pin_setflags(device_t dev, device_t child, uint32_t pin, uint32_t flags) { struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev); struct gpiobus_ivar *devi = GPIOBUS_IVAR(child); uint32_t caps; if (pin >= devi->npins) return (EINVAL); if (GPIO_PIN_GETCAPS(sc->sc_dev, devi->pins[pin], &caps) != 0) return (EINVAL); if (gpio_check_flags(caps, flags) != 0) return (EINVAL); return (GPIO_PIN_SETFLAGS(sc->sc_dev, devi->pins[pin], flags)); }
static int a10codec_mixer_init(struct snd_mixer *m) { struct a10codec_info *sc = mix_getdevinfo(m); pcell_t prop[4]; phandle_t node; device_t gpio; uint32_t val; ssize_t len; int pin; mix_setdevs(m, SOUND_MASK_VOLUME | SOUND_MASK_LINE | SOUND_MASK_RECLEV); mix_setrecdevs(m, SOUND_MASK_LINE | SOUND_MASK_LINE1 | SOUND_MASK_MIC); /* Unmute input source to PA */ val = CODEC_READ(sc, AC_DAC_ACTL); val |= DAC_ACTL_PAMUTE; CODEC_WRITE(sc, AC_DAC_ACTL, val); /* Enable PA */ val = CODEC_READ(sc, AC_ADC_ACTL); val |= ADC_ACTL_PA_EN; CODEC_WRITE(sc, AC_ADC_ACTL, val); /* Unmute PA */ node = ofw_bus_get_node(sc->dev); len = OF_getencprop(node, "allwinner,pa-gpios", prop, sizeof(prop)); if (len > 0 && (len / sizeof(prop[0])) == 4) { gpio = OF_device_from_xref(prop[0]); if (gpio != NULL) { pin = prop[1] * 32 + prop[2]; GPIO_PIN_SETFLAGS(gpio, pin, GPIO_PIN_OUTPUT); GPIO_PIN_SET(gpio, pin, GPIO_PIN_LOW); } } return (0); }
static int gpioc_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag, struct thread *td) { device_t bus; int max_pin, res; struct gpioc_softc *sc = cdev->si_drv1; struct gpio_pin pin; struct gpio_req req; uint32_t caps; bus = GPIO_GET_BUS(sc->sc_pdev); if (bus == NULL) return (EINVAL); switch (cmd) { case GPIOMAXPIN: max_pin = -1; res = GPIO_PIN_MAX(sc->sc_pdev, &max_pin); bcopy(&max_pin, arg, sizeof(max_pin)); break; case GPIOGETCONFIG: bcopy(arg, &pin, sizeof(pin)); dprintf("get config pin %d\n", pin.gp_pin); res = GPIO_PIN_GETFLAGS(sc->sc_pdev, pin.gp_pin, &pin.gp_flags); /* Fail early */ if (res) break; GPIO_PIN_GETCAPS(sc->sc_pdev, pin.gp_pin, &pin.gp_caps); GPIOBUS_PIN_GETNAME(bus, pin.gp_pin, pin.gp_name); bcopy(&pin, arg, sizeof(pin)); break; case GPIOSETCONFIG: bcopy(arg, &pin, sizeof(pin)); dprintf("set config pin %d\n", pin.gp_pin); res = GPIO_PIN_GETCAPS(sc->sc_pdev, pin.gp_pin, &caps); if (res == 0) res = gpio_check_flags(caps, pin.gp_flags); if (res == 0) res = GPIO_PIN_SETFLAGS(sc->sc_pdev, pin.gp_pin, pin.gp_flags); break; case GPIOGET: bcopy(arg, &req, sizeof(req)); res = GPIO_PIN_GET(sc->sc_pdev, req.gp_pin, &req.gp_value); dprintf("read pin %d -> %d\n", req.gp_pin, req.gp_value); bcopy(&req, arg, sizeof(req)); break; case GPIOSET: bcopy(arg, &req, sizeof(req)); res = GPIO_PIN_SET(sc->sc_pdev, req.gp_pin, req.gp_value); dprintf("write pin %d -> %d\n", req.gp_pin, req.gp_value); break; case GPIOTOGGLE: bcopy(arg, &req, sizeof(req)); dprintf("toggle pin %d\n", req.gp_pin); res = GPIO_PIN_TOGGLE(sc->sc_pdev, req.gp_pin); break; case GPIOSETNAME: bcopy(arg, &pin, sizeof(pin)); dprintf("set name on pin %d\n", pin.gp_pin); res = GPIOBUS_PIN_SETNAME(bus, pin.gp_pin, pin.gp_name); break; default: return (ENOTTY); break; } return (res); }
static int a10_ehci_attach(device_t self) { ehci_softc_t *sc = device_get_softc(self); bus_space_handle_t bsh; device_t sc_gpio_dev; int err; int rid; uint32_t reg_value = 0; /* initialise some bus fields */ sc->sc_bus.parent = self; sc->sc_bus.devices = sc->sc_devices; sc->sc_bus.devices_max = EHCI_MAX_DEVICES; /* get all DMA memory */ if (usb_bus_mem_alloc_all(&sc->sc_bus, USB_GET_DMA_TAG(self), &ehci_iterate_hw_softc)) { return (ENOMEM); } sc->sc_bus.usbrev = USB_REV_2_0; rid = 0; sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (!sc->sc_io_res) { device_printf(self, "Could not map memory\n"); goto error; } sc->sc_io_tag = rman_get_bustag(sc->sc_io_res); sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); bsh = rman_get_bushandle(sc->sc_io_res); sc->sc_io_size = rman_get_size(sc->sc_io_res); if (bus_space_subregion(sc->sc_io_tag, bsh, 0x00, sc->sc_io_size, &sc->sc_io_hdl) != 0) panic("%s: unable to subregion USB host registers", device_get_name(self)); rid = 0; sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); if (sc->sc_irq_res == NULL) { device_printf(self, "Could not allocate irq\n"); goto error; } sc->sc_bus.bdev = device_add_child(self, "usbus", -1); if (!sc->sc_bus.bdev) { device_printf(self, "Could not add USB device\n"); goto error; } device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); device_set_desc(sc->sc_bus.bdev, EHCI_HC_DEVSTR); sprintf(sc->sc_vendor, "Allwinner"); /* Get the GPIO device, we need this to give power to USB */ sc_gpio_dev = devclass_get_device(devclass_find("gpio"), 0); if (sc_gpio_dev == NULL) { device_printf(self, "Error: failed to get the GPIO device\n"); goto error; } err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, NULL, (driver_intr_t *)ehci_interrupt, sc, &sc->sc_intr_hdl); if (err) { device_printf(self, "Could not setup irq, %d\n", err); sc->sc_intr_hdl = NULL; goto error; } sc->sc_flags |= EHCI_SCFLG_DONTRESET; /* Enable clock for USB */ a10_clk_usb_activate(); /* Give power to USB */ GPIO_PIN_SETFLAGS(sc_gpio_dev, GPIO_USB2_PWR, GPIO_PIN_OUTPUT); GPIO_PIN_SET(sc_gpio_dev, GPIO_USB2_PWR, GPIO_PIN_HIGH); /* Give power to USB */ GPIO_PIN_SETFLAGS(sc_gpio_dev, GPIO_USB1_PWR, GPIO_PIN_OUTPUT); GPIO_PIN_SET(sc_gpio_dev, GPIO_USB1_PWR, GPIO_PIN_HIGH); /* Enable passby */ reg_value = A10_READ_4(sc, SW_USB_PMU_IRQ_ENABLE); reg_value |= SW_AHB_INCR8; /* AHB INCR8 enable */ reg_value |= SW_AHB_INCR4; /* AHB burst type INCR4 enable */ reg_value |= SW_AHB_INCRX_ALIGN; /* AHB INCRX align enable */ reg_value |= SW_ULPI_BYPASS; /* ULPI bypass enable */ A10_WRITE_4(sc, SW_USB_PMU_IRQ_ENABLE, reg_value); /* Configure port */ reg_value = A10_READ_4(sc, SW_SDRAM_REG_HPCR_USB2); reg_value |= SW_SDRAM_BP_HPCR_ACCESS; A10_WRITE_4(sc, SW_SDRAM_REG_HPCR_USB2, reg_value); err = ehci_init(sc); if (!err) { err = device_probe_and_attach(sc->sc_bus.bdev); } if (err) { device_printf(self, "USB init failed err=%d\n", err); goto error; } return (0); error: a10_ehci_detach(self); return (ENXIO); }
static int dcu_attach(device_t dev) { struct panel_info panel; struct dcu_softc *sc; device_t gpio_dev; int err; sc = device_get_softc(dev); sc->dev = dev; if (bus_alloc_resources(dev, dcu_spec, sc->res)) { device_printf(dev, "could not allocate resources\n"); return (ENXIO); } /* Memory interface */ sc->bst = rman_get_bustag(sc->res[0]); sc->bsh = rman_get_bushandle(sc->res[0]); /* Setup interrupt handler */ err = bus_setup_intr(dev, sc->res[1], INTR_TYPE_BIO | INTR_MPSAFE, NULL, dcu_intr, sc, &sc->ih); if (err) { device_printf(dev, "Unable to alloc interrupt resource.\n"); return (ENXIO); } if (get_panel_info(sc, &panel)) { device_printf(dev, "Can't get panel info\n"); return (ENXIO); } sc->panel = &panel; /* Bypass timing control (used for raw lcd panels) */ tcon_bypass(); /* Get the GPIO device, we need this to give power to USB */ gpio_dev = devclass_get_device(devclass_find("gpio"), 0); if (gpio_dev == NULL) { device_printf(sc->dev, "Error: failed to get the GPIO dev\n"); return (1); } /* Turn on backlight */ /* TODO: Use FlexTimer/PWM */ GPIO_PIN_SETFLAGS(gpio_dev, panel.backlight_pin, GPIO_PIN_OUTPUT); GPIO_PIN_SET(gpio_dev, panel.backlight_pin, GPIO_PIN_HIGH); sc->sc_info.fb_width = panel.width; sc->sc_info.fb_height = panel.height; sc->sc_info.fb_stride = sc->sc_info.fb_width * 3; sc->sc_info.fb_bpp = sc->sc_info.fb_depth = 24; sc->sc_info.fb_size = sc->sc_info.fb_height * sc->sc_info.fb_stride; sc->sc_info.fb_vbase = (intptr_t)contigmalloc(sc->sc_info.fb_size, M_DEVBUF, M_ZERO, 0, ~0, PAGE_SIZE, 0); sc->sc_info.fb_pbase = (intptr_t)vtophys(sc->sc_info.fb_vbase); #if 0 printf("%dx%d [%d]\n", sc->sc_info.fb_width, sc->sc_info.fb_height, sc->sc_info.fb_stride); printf("pbase == 0x%08x\n", sc->sc_info.fb_pbase); #endif memset((int8_t *)sc->sc_info.fb_vbase, 0x0, sc->sc_info.fb_size); dcu_init(sc); sc->sc_info.fb_name = device_get_nameunit(dev); /* Ask newbus to attach framebuffer device to me. */ sc->sc_fbd = device_add_child(dev, "fbd", device_get_unit(dev)); if (sc->sc_fbd == NULL) device_printf(dev, "Can't attach fbd device\n"); if (device_probe_and_attach(sc->sc_fbd) != 0) { device_printf(sc->dev, "Failed to attach fbd device\n"); } return (0); }
/** * omap_ehci_init - initialises the USB host EHCI controller * @isc: omap ehci device context * * This initialisation routine is quite heavily based on the work done by the * OMAP Linux team (for which I thank them very much). The init sequence is * almost identical, diverging only for the FreeBSD specifics. * * LOCKING: * none * * RETURNS: * 0 on success, a negative error code on failure. */ static int omap_ehci_init(struct omap_ehci_softc *isc) { unsigned long timeout; int ret = 0; uint8_t tll_ch_mask = 0; uint32_t reg = 0; int reset_performed = 0; int i; device_printf(isc->sc_dev, "Starting TI EHCI USB Controller\n"); /* Enable Clocks for high speed USBHOST */ ti_prcm_clk_enable(USBHSHOST_CLK); /* Hold the PHY in reset while configuring */ for (int i = 0; i < 3; i++) { if (isc->phy_reset[i]) { /* Configure the GPIO to drive low (hold in reset) */ if ((isc->reset_gpio_pin[i] != -1) && (isc->sc_gpio_dev != NULL)) { GPIO_PIN_SETFLAGS(isc->sc_gpio_dev, isc->reset_gpio_pin[i], GPIO_PIN_OUTPUT); GPIO_PIN_SET(isc->sc_gpio_dev, isc->reset_gpio_pin[i], GPIO_PIN_LOW); reset_performed = 1; } } } /* Hold the PHY in RESET for enough time till DIR is high */ if (reset_performed) DELAY(10); /* Read the UHH revision */ isc->ehci_rev = omap_uhh_read_4(isc, OMAP_USBHOST_UHH_REVISION); device_printf(isc->sc_dev, "UHH revision 0x%08x\n", isc->ehci_rev); /* Initilise the low level interface module(s) */ if (isc->ehci_rev == OMAP_EHCI_REV1) { /* Enable the USB TLL */ ti_prcm_clk_enable(USBTLL_CLK); /* Perform TLL soft reset, and wait until reset is complete */ omap_tll_write_4(isc, OMAP_USBTLL_SYSCONFIG, TLL_SYSCONFIG_SOFTRESET); /* Set the timeout to 100ms*/ timeout = (hz < 10) ? 1 : ((100 * hz) / 1000); /* Wait for TLL reset to complete */ while ((omap_tll_read_4(isc, OMAP_USBTLL_SYSSTATUS) & TLL_SYSSTATUS_RESETDONE) == 0x00) { /* Sleep for a tick */ pause("USBRESET", 1); if (timeout-- == 0) { device_printf(isc->sc_dev, "TLL reset operation timed out\n"); ret = EINVAL; goto err_sys_status; } } device_printf(isc->sc_dev, "TLL RESET DONE\n"); /* CLOCKACTIVITY = 1 : OCP-derived internal clocks ON during idle * SIDLEMODE = 2 : Smart-idle mode. Sidleack asserted after Idlereq * assertion when no more activity on the USB. * ENAWAKEUP = 1 : Wakeup generation enabled */ omap_tll_write_4(isc, OMAP_USBTLL_SYSCONFIG, TLL_SYSCONFIG_ENAWAKEUP | TLL_SYSCONFIG_AUTOIDLE | TLL_SYSCONFIG_SIDLE_SMART_IDLE | TLL_SYSCONFIG_CACTIVITY); } else if (isc->ehci_rev == OMAP_EHCI_REV2) { /* For OMAP44xx devices you have to enable the per-port clocks: * PHY_MODE - External ULPI clock * TTL_MODE - Internal UTMI clock * HSIC_MODE - Internal 480Mhz and 60Mhz clocks */ if (isc->ehci_rev == OMAP_EHCI_REV2) { if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) { ti_prcm_clk_set_source(USBP1_PHY_CLK, EXT_CLK); ti_prcm_clk_enable(USBP1_PHY_CLK); } else if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) ti_prcm_clk_enable(USBP1_UTMI_CLK); else if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_HSIC) ti_prcm_clk_enable(USBP1_HSIC_CLK); if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) { ti_prcm_clk_set_source(USBP2_PHY_CLK, EXT_CLK); ti_prcm_clk_enable(USBP2_PHY_CLK); } else if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) ti_prcm_clk_enable(USBP2_UTMI_CLK); else if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_HSIC) ti_prcm_clk_enable(USBP2_HSIC_CLK); } } /* Put UHH in SmartIdle/SmartStandby mode */ reg = omap_uhh_read_4(isc, OMAP_USBHOST_UHH_SYSCONFIG); if (isc->ehci_rev == OMAP_EHCI_REV1) { reg &= ~(UHH_SYSCONFIG_SIDLEMODE_MASK | UHH_SYSCONFIG_MIDLEMODE_MASK); reg |= (UHH_SYSCONFIG_ENAWAKEUP | UHH_SYSCONFIG_AUTOIDLE | UHH_SYSCONFIG_CLOCKACTIVITY | UHH_SYSCONFIG_SIDLEMODE_SMARTIDLE | UHH_SYSCONFIG_MIDLEMODE_SMARTSTANDBY); } else if (isc->ehci_rev == OMAP_EHCI_REV2) { reg &= ~UHH_SYSCONFIG_IDLEMODE_MASK; reg |= UHH_SYSCONFIG_IDLEMODE_NOIDLE; reg &= ~UHH_SYSCONFIG_STANDBYMODE_MASK; reg |= UHH_SYSCONFIG_STANDBYMODE_NOSTDBY; } omap_uhh_write_4(isc, OMAP_USBHOST_UHH_SYSCONFIG, reg); device_printf(isc->sc_dev, "OMAP_UHH_SYSCONFIG: 0x%08x\n", reg); reg = omap_uhh_read_4(isc, OMAP_USBHOST_UHH_HOSTCONFIG); /* Setup ULPI bypass and burst configurations */ reg |= (UHH_HOSTCONFIG_ENA_INCR4 | UHH_HOSTCONFIG_ENA_INCR8 | UHH_HOSTCONFIG_ENA_INCR16); reg &= ~UHH_HOSTCONFIG_ENA_INCR_ALIGN; if (isc->ehci_rev == OMAP_EHCI_REV1) { if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_UNKNOWN) reg &= ~UHH_HOSTCONFIG_P1_CONNECT_STATUS; if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_UNKNOWN) reg &= ~UHH_HOSTCONFIG_P2_CONNECT_STATUS; if (isc->port_mode[2] == EHCI_HCD_OMAP_MODE_UNKNOWN) reg &= ~UHH_HOSTCONFIG_P3_CONNECT_STATUS; /* Bypass the TLL module for PHY mode operation */ if ((isc->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) || (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) || (isc->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY)) reg &= ~UHH_HOSTCONFIG_P1_ULPI_BYPASS; else reg |= UHH_HOSTCONFIG_P1_ULPI_BYPASS; } else if (isc->ehci_rev == OMAP_EHCI_REV2) { reg |= UHH_HOSTCONFIG_APP_START_CLK; /* Clear port mode fields for PHY mode*/ reg &= ~UHH_HOSTCONFIG_P1_MODE_MASK; reg &= ~UHH_HOSTCONFIG_P2_MODE_MASK; if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) reg |= UHH_HOSTCONFIG_P1_MODE_UTMI_PHY; else if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_HSIC) reg |= UHH_HOSTCONFIG_P1_MODE_HSIC; if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) reg |= UHH_HOSTCONFIG_P2_MODE_UTMI_PHY; else if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_HSIC) reg |= UHH_HOSTCONFIG_P2_MODE_HSIC; } omap_uhh_write_4(isc, OMAP_USBHOST_UHH_HOSTCONFIG, reg); device_printf(isc->sc_dev, "UHH setup done, uhh_hostconfig=0x%08x\n", reg); /* I found the code and comments in the Linux EHCI driver - thanks guys :) * * "An undocumented "feature" in the OMAP3 EHCI controller, causes suspended * ports to be taken out of suspend when the USBCMD.Run/Stop bit is cleared * (for example when we do ehci_bus_suspend). This breaks suspend-resume if * the root-hub is allowed to suspend. Writing 1 to this undocumented * register bit disables this feature and restores normal behavior." */ #if 0 omap_ehci_write_4(isc, OMAP_USBHOST_INSNREG04, OMAP_USBHOST_INSNREG04_DISABLE_UNSUSPEND); #endif /* If any of the ports are configured in TLL mode, enable them */ if ((isc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) || (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) || (isc->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL)) { if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) tll_ch_mask |= 0x1; if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) tll_ch_mask |= 0x2; if (isc->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL) tll_ch_mask |= 0x4; /* Enable UTMI mode for required TLL channels */ omap_ehci_utmi_init(isc, tll_ch_mask); } /* Release the PHY reset signal now we have configured everything */ if (reset_performed) { /* Delay for 10ms */ DELAY(10000); for (i = 0; i < 3; i++) { /* Release reset */ if (isc->phy_reset[i] && (isc->reset_gpio_pin[i] != -1) && (isc->sc_gpio_dev != NULL)) { GPIO_PIN_SET(isc->sc_gpio_dev, isc->reset_gpio_pin[i], GPIO_PIN_HIGH); } } } /* Set the interrupt threshold control, it controls the maximum rate at * which the host controller issues interrupts. We set it to 1 microframe * at startup - the default is 8 mircoframes (equates to 1ms). */ reg = omap_ehci_read_4(isc, OMAP_USBHOST_USBCMD); reg &= 0xff00ffff; reg |= (1 << 16); omap_ehci_write_4(isc, OMAP_USBHOST_USBCMD, reg); /* Soft reset the PHY using PHY reset command over ULPI */ if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) omap_ehci_soft_phy_reset(isc, 0); if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) omap_ehci_soft_phy_reset(isc, 1); return(0); err_sys_status: /* Disable the TLL clocks */ ti_prcm_clk_disable(USBTLL_CLK); /* Disable Clocks for USBHOST */ ti_prcm_clk_disable(USBHSHOST_CLK); return(ret); }
/** * ti_mmchs_attach - attach function for the driver * @dev: mmc device handle * * Driver initialisation, sets-up the bus mappings, DMA mapping/channels and * the actual controller by calling ti_mmchs_init(). * * RETURNS: * Returns 0 on success or a negative error code. */ static int ti_mmchs_attach(device_t dev) { struct ti_mmchs_softc *sc = device_get_softc(dev); int unit = device_get_unit(dev); int err; device_t child; /* Save the device and bus tag */ sc->sc_dev = dev; /* Initiate the mtex lock */ TI_MMCHS_LOCK_INIT(sc); /* Indicate the DMA channels haven't yet been allocated */ sc->sc_dmach_rd = (unsigned int)-1; sc->sc_dmach_wr = (unsigned int)-1; /* Get the hint'ed write detect pin */ if (resource_int_value("ti_mmchs", unit, "wp_gpio", &sc->sc_wp_gpio_pin) != 0){ sc->sc_wp_gpio_pin = -1; } else { /* Get the GPIO device, we need this for the write protect pin */ sc->sc_gpio_dev = devclass_get_device(devclass_find("gpio"), 0); if (sc->sc_gpio_dev == NULL) device_printf(dev, "Error: failed to get the GPIO device\n"); else GPIO_PIN_SETFLAGS(sc->sc_gpio_dev, sc->sc_wp_gpio_pin, GPIO_PIN_INPUT); } /* Get the TWL voltage regulator device, we need this to for setting the * voltage of the bus on certain OMAP platforms. */ sc->sc_vreg_name = NULL; /* TODO: add voltage regulator knob to FDT */ #ifdef notyet sc->sc_vreg_dev = devclass_get_device(devclass_find("twl_vreg"), 0); if (sc->sc_vreg_dev == NULL) { device_printf(dev, "Error: failed to get the votlage regulator" " device\n"); sc->sc_vreg_name = NULL; } #endif /* Activate the device */ err = ti_mmchs_activate(dev); if (err) goto out; /* Initialise the controller */ ti_mmchs_hw_init(dev); /* Activate the interrupt and attach a handler */ err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE, NULL, ti_mmchs_intr, sc, &sc->sc_irq_h); if (err != 0) goto out; /* Add host details */ sc->host.f_min = sc->sc_ref_freq / 1023; sc->host.f_max = sc->sc_ref_freq; sc->host.host_ocr = MMC_OCR_290_300 | MMC_OCR_300_310; sc->host.caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; child = device_add_child(dev, "mmc", 0); device_set_ivars(dev, &sc->host); err = bus_generic_attach(dev); out: if (err) { TI_MMCHS_LOCK_DESTROY(sc); ti_mmchs_deactivate(dev); if (sc->sc_dmach_rd != (unsigned int)-1) ti_sdma_deactivate_channel(sc->sc_dmach_rd); if (sc->sc_dmach_wr != (unsigned int)-1) ti_sdma_deactivate_channel(sc->sc_dmach_wr); } return (err); }
static int aml8726_usb_phy_attach(device_t dev) { struct aml8726_usb_phy_softc *sc = device_get_softc(dev); int err; int npwr_en; pcell_t *prop; phandle_t node; ssize_t len; uint32_t div; uint32_t i; uint32_t mode_a; uint32_t mode_b; uint32_t value; sc->dev = dev; if (aml8726_usb_phy_mode("/soc/usb@c9040000", &mode_a) != 0) { device_printf(dev, "missing usb@c9040000 node in FDT\n"); return (ENXIO); } if (aml8726_usb_phy_mode("/soc/usb@c90c0000", &mode_b) != 0) { device_printf(dev, "missing usb@c90c0000 node in FDT\n"); return (ENXIO); } if (bus_alloc_resources(dev, aml8726_usb_phy_spec, sc->res)) { device_printf(dev, "can not allocate resources for device\n"); return (ENXIO); } node = ofw_bus_get_node(dev); err = 0; len = OF_getencprop_alloc(node, "usb-pwr-en", 3 * sizeof(pcell_t), (void **)&prop); npwr_en = (len > 0) ? len : 0; sc->npwr_en = 0; sc->pwr_en = (struct aml8726_usb_phy_gpio *) malloc(npwr_en * sizeof (*sc->pwr_en), M_DEVBUF, M_WAITOK); for (i = 0; i < npwr_en; i++) { sc->pwr_en[i].dev = OF_device_from_xref(prop[i * 3]); sc->pwr_en[i].pin = prop[i * 3 + 1]; sc->pwr_en[i].pol = prop[i * 3 + 2]; if (sc->pwr_en[i].dev == NULL) { err = 1; break; } } free(prop, M_OFWPROP); if (err) { device_printf(dev, "unable to parse gpio\n"); goto fail; } /* Turn on power by setting pin and then enabling output driver. */ for (i = 0; i < npwr_en; i++) { if (GPIO_PIN_SET(sc->pwr_en[i].dev, sc->pwr_en[i].pin, PIN_ON_FLAG(sc->pwr_en[i].pol)) != 0 || GPIO_PIN_SETFLAGS(sc->pwr_en[i].dev, sc->pwr_en[i].pin, GPIO_PIN_OUTPUT) != 0) { device_printf(dev, "could not use gpio to control power\n"); goto fail; } sc->npwr_en++; } /* * Configure the clock source and divider. */ div = 2; value = CSR_READ_4(sc, AML_USB_PHY_CFG_REG); value &= ~(AML_USB_PHY_CFG_CLK_DIV_MASK | AML_USB_PHY_CFG_CLK_SEL_MASK); value &= ~(AML_USB_PHY_CFG_A_RST | AML_USB_PHY_CFG_B_RST); value &= ~(AML_USB_PHY_CFG_A_PLL_RST | AML_USB_PHY_CFG_B_PLL_RST); value &= ~(AML_USB_PHY_CFG_A_PHYS_RST | AML_USB_PHY_CFG_B_PHYS_RST); value &= ~(AML_USB_PHY_CFG_A_POR | AML_USB_PHY_CFG_B_POR); value |= AML_USB_PHY_CFG_CLK_SEL_XTAL; value |= ((div - 1) << AML_USB_PHY_CFG_CLK_DIV_SHIFT) & AML_USB_PHY_CFG_CLK_DIV_MASK; value |= AML_USB_PHY_CFG_CLK_EN; CSR_WRITE_4(sc, AML_USB_PHY_CFG_REG, value); CSR_BARRIER(sc, AML_USB_PHY_CFG_REG); /* * Issue the reset sequence. */ value |= (AML_USB_PHY_CFG_A_RST | AML_USB_PHY_CFG_B_RST); CSR_WRITE_4(sc, AML_USB_PHY_CFG_REG, value); CSR_BARRIER(sc, AML_USB_PHY_CFG_REG); DELAY(200); value &= ~(AML_USB_PHY_CFG_A_RST | AML_USB_PHY_CFG_B_RST); CSR_WRITE_4(sc, AML_USB_PHY_CFG_REG, value); CSR_BARRIER(sc, AML_USB_PHY_CFG_REG); DELAY(200); value |= (AML_USB_PHY_CFG_A_PLL_RST | AML_USB_PHY_CFG_B_PLL_RST); CSR_WRITE_4(sc, AML_USB_PHY_CFG_REG, value); CSR_BARRIER(sc, AML_USB_PHY_CFG_REG); DELAY(200); value &= ~(AML_USB_PHY_CFG_A_PLL_RST | AML_USB_PHY_CFG_B_PLL_RST); CSR_WRITE_4(sc, AML_USB_PHY_CFG_REG, value); CSR_BARRIER(sc, AML_USB_PHY_CFG_REG); DELAY(200); value |= (AML_USB_PHY_CFG_A_PHYS_RST | AML_USB_PHY_CFG_B_PHYS_RST); CSR_WRITE_4(sc, AML_USB_PHY_CFG_REG, value); CSR_BARRIER(sc, AML_USB_PHY_CFG_REG); DELAY(200); value &= ~(AML_USB_PHY_CFG_A_PHYS_RST | AML_USB_PHY_CFG_B_PHYS_RST); CSR_WRITE_4(sc, AML_USB_PHY_CFG_REG, value); CSR_BARRIER(sc, AML_USB_PHY_CFG_REG); DELAY(200); value |= (AML_USB_PHY_CFG_A_POR | AML_USB_PHY_CFG_B_POR); CSR_WRITE_4(sc, AML_USB_PHY_CFG_REG, value); CSR_BARRIER(sc, AML_USB_PHY_CFG_REG); DELAY(200); /* * Enable by clearing the power on reset. */ value &= ~(AML_USB_PHY_CFG_A_POR | AML_USB_PHY_CFG_B_POR); CSR_WRITE_4(sc, AML_USB_PHY_CFG_REG, value); CSR_BARRIER(sc, AML_USB_PHY_CFG_REG); DELAY(200); /* * Check if the clock was detected. */ value = CSR_READ_4(sc, AML_USB_PHY_CFG_REG); if ((value & AML_USB_PHY_CFG_CLK_DETECTED) != AML_USB_PHY_CFG_CLK_DETECTED) device_printf(dev, "PHY Clock not detected\n"); /* * Configure the mode for each port. */ value = CSR_READ_4(sc, AML_USB_PHY_MISC_A_REG); value &= ~(AML_USB_PHY_MISC_ID_OVERIDE_EN | AML_USB_PHY_MISC_ID_OVERIDE_DEVICE | AML_USB_PHY_MISC_ID_OVERIDE_HOST); value |= mode_a; CSR_WRITE_4(sc, AML_USB_PHY_MISC_A_REG, value); value = CSR_READ_4(sc, AML_USB_PHY_MISC_B_REG); value &= ~(AML_USB_PHY_MISC_ID_OVERIDE_EN | AML_USB_PHY_MISC_ID_OVERIDE_DEVICE | AML_USB_PHY_MISC_ID_OVERIDE_HOST); value |= mode_b; CSR_WRITE_4(sc, AML_USB_PHY_MISC_B_REG, value); CSR_BARRIER(sc, AML_USB_PHY_MISC_B_REG); return (0); fail: /* In the event of problems attempt to turn things back off. */ i = sc->npwr_en; while (i-- != 0) { GPIO_PIN_SET(sc->pwr_en[i].dev, sc->pwr_en[i].pin, PIN_OFF_FLAG(sc->pwr_en[i].pol)); } free (sc->pwr_en, M_DEVBUF); sc->pwr_en = NULL; bus_release_resources(dev, aml8726_usb_phy_spec, sc->res); return (ENXIO); }