void target_usb_init(void) { uint32_t val; /* Select and enable external configuration with USB PHY */ ulpi_write(ULPI_MISC_A_VBUSVLDEXTSEL | ULPI_MISC_A_VBUSVLDEXT, ULPI_MISC_A_SET); /* Enable sess_vld */ val = readl(USB_GENCONFIG_2) | GEN2_SESS_VLD_CTRL_EN; writel(val, USB_GENCONFIG_2); /* Enable external vbus configuration in the LINK */ val = readl(USB_USBCMD); val |= SESS_VLD_CTRL; writel(val, USB_USBCMD); }
static int msm_phy_notify_disconnect(struct usb_phy *phy, enum usb_device_speed speed) { int val; /* * Put the transceiver in non-driving mode. Otherwise host * may not detect soft-disconnection. */ val = ulpi_read(phy, ULPI_FUNC_CTRL); val &= ~ULPI_FUNC_CTRL_OPMODE_MASK; val |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING; ulpi_write(phy, val, ULPI_FUNC_CTRL); return 0; }
static void ehci_msm_enable_ulpi_control(struct usb_hcd *hcd, u32 linestate) { struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd); int val; switch (linestate) { case PORT_RESET: val = ulpi_read(mehci, HSIC_DBG1); val |= ULPI_MANUAL_ENABLE; val &= ~(ULPI_LINESTATE_DATA | ULPI_LINESTATE_STROBE); ulpi_write(mehci, val, HSIC_DBG1); break; default: pr_info("%s: Unknown linestate:%0x\n", __func__, linestate); } }
static void msm7201_setup_phy(struct usb_hcd *hcd) { /* struct msm7201_usb_priv *msm7201 = hcd_to_msm7201(hcd); int *seq = msm7201->phy_init_seq; if (!seq) return;*/ static int seq[] = { 0x40, 0x31, 0x1D, 0x0D, 0x1D, 0x10, -1 }; int p=0; while (seq[p] >= 0) { ulpi_write(hcd, seq[p], seq[p+1]); p += 2; } }
/* If this function returns < 0, the phy reset failed and we cannot * continue at this point. The only solution is to wait until the next * cable disconnect/reconnect to bring the phy back */ static int usb_phy_reset(struct usb_info *ui) { u32 val; int ret; int retries; if (!ui->phy_reset) return 0; if (ui->hw_reset) ui->hw_reset(1); ui->phy_reset(); if (ui->hw_reset) ui->hw_reset(0); #if defined(CONFIG_ARCH_QSD8X50) val = readl(USB_PORTSC) & ~PORTSC_PTS_MASK; writel(val | PORTSC_PTS_ULPI, USB_PORTSC); /* XXX: only necessary for pre-45nm internal PHYs. */ for (retries = 3; retries > 0; retries--) { ret = ulpi_write(ui, ULPI_FUNC_SUSPENDM, ULPI_FUNC_CTRL_CLR); if (!ret) break; ui->phy_reset(); } if (!retries) return -1; /* this reset calibrates the phy, if the above write succeeded */ ui->phy_reset(); /* XXX: pre-45nm internal phys have a known issue which can cause them * to lockup on reset. If ULPI accesses fail, try resetting the phy * again */ for (retries = 3; retries > 0; retries--) { ret = ulpi_read(ui, ULPI_DEBUG_REG); if (ret != 0xffffffff) break; ui->phy_reset(); } if (!retries) return -1; #endif pr_info("msm_hsusb_phy_reset: success\n"); return 0; }
static int msm_otg_remove(struct platform_device *pdev) { struct msm_otg *motg = platform_get_drvdata(pdev); struct usb_phy *phy = &motg->phy; int cnt = 0; if (phy->otg->host || phy->otg->gadget) return -EBUSY; msm_otg_debugfs_cleanup(); cancel_delayed_work_sync(&motg->chg_work); cancel_work_sync(&motg->sm_work); pm_runtime_resume(&pdev->dev); device_init_wakeup(&pdev->dev, 0); pm_runtime_disable(&pdev->dev); usb_remove_phy(phy); disable_irq(motg->irq); /* * Put PHY in low power mode. */ ulpi_read(phy, 0x14); ulpi_write(phy, 0x08, 0x09); writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC); while (cnt < PHY_SUSPEND_TIMEOUT_USEC) { if (readl(USB_PORTSC) & PORTSC_PHCD) break; udelay(1); cnt++; } if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) dev_err(phy->dev, "Unable to suspend PHY\n"); clk_disable_unprepare(motg->pclk); clk_disable_unprepare(motg->clk); if (!IS_ERR(motg->core_clk)) clk_disable_unprepare(motg->core_clk); msm_hsusb_ldo_init(motg, 0); pm_runtime_set_suspended(&pdev->dev); return 0; }
static int msm_hsusb_ulpi_write_with_reset(void __iomem *usb_base, unsigned val, unsigned reg) { int temp; int res; for (temp = 0; temp < ULPI_VERIFY_MAX_LOOP_COUNT; temp++) { res = ulpi_write(usb_base, val, reg); if (!res) return 0; msm_hsusb_apps_reset_phy(); } pr_err("%s: ulpi write failed for %d times\n", __func__, ULPI_VERIFY_MAX_LOOP_COUNT); return -1; }
/* Do target specific usb initialization */ void target_usb_init(void) { uint32_t val; /* Enable secondary USB PHY on DragonBoard8074 */ if (board_hardware_id() == HW_PLATFORM_DRAGON) { /* Route ChipIDea to use secondary USB HS port2 */ writel_relaxed(1, USB2_PHY_SEL); /* Enable access to secondary PHY by clamping the low * voltage interface between DVDD of the PHY and Vddcx * (set bit16 (USB2_PHY_HS2_DIG_CLAMP_N_2) = 1) */ writel_relaxed(readl_relaxed(USB_OTG_HS_PHY_SEC_CTRL) | 0x00010000, USB_OTG_HS_PHY_SEC_CTRL); /* Perform power-on-reset of the PHY. * Delay values are arbitrary */ writel_relaxed(readl_relaxed(USB_OTG_HS_PHY_CTRL)|1, USB_OTG_HS_PHY_CTRL); thread_sleep(10); writel_relaxed(readl_relaxed(USB_OTG_HS_PHY_CTRL) & 0xFFFFFFFE, USB_OTG_HS_PHY_CTRL); thread_sleep(10); /* Enable HSUSB PHY port for ULPI interface, * then configure related parameters within the PHY */ writel_relaxed(((readl_relaxed(USB_PORTSC) & 0xC0000000) | 0x8c000004), USB_PORTSC); } if (target_needs_vbus_mimic()) { /* Select and enable external configuration with USB PHY */ ulpi_write(ULPI_MISC_A_VBUSVLDEXTSEL | ULPI_MISC_A_VBUSVLDEXT, ULPI_MISC_A_SET); /* Enable sess_vld */ val = readl(USB_GENCONFIG_2) | GEN2_SESS_VLD_CTRL_EN; writel(val, USB_GENCONFIG_2); /* Enable external vbus configuration in the LINK */ val = readl(USB_USBCMD); val |= SESS_VLD_CTRL; writel(val, USB_USBCMD); } }
void ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg) { uint32_t port = OTG_BASE_ADDR + (0x200 * CONFIG_MXC_USB_PORT); struct usb_ehci *ehci = (struct usb_ehci *)port; struct ulpi_regs *ulpi = (struct ulpi_regs *)0; struct ulpi_viewport ulpi_vp; ulpi_vp.viewport_addr = (u32)&ehci->ulpi_viewpoint; ulpi_vp.port_num = 0; ulpi_write(&ulpi_vp, &ulpi->otg_ctrl_set, ULPI_OTG_CHRGVBUS); mdelay(50); /* terminate the reset */ *reg = ehci_readl(status_reg); *reg |= EHCI_PS_PE; }
static void msm_chg_enable_secondary_det(struct msm_otg *motg) { struct usb_phy *phy = &motg->phy; u32 chg_det; switch (motg->pdata->phy_type) { case CI_45NM_INTEGRATED_PHY: chg_det = ulpi_read(phy, 0x34); /* Turn off charger block */ chg_det |= ~(1 << 1); ulpi_write(phy, chg_det, 0x34); udelay(20); /* control chg block via ULPI */ chg_det &= ~(1 << 3); ulpi_write(phy, chg_det, 0x34); /* put it in host mode for enabling D- source */ chg_det &= ~(1 << 2); ulpi_write(phy, chg_det, 0x34); /* Turn on chg detect block */ chg_det &= ~(1 << 1); ulpi_write(phy, chg_det, 0x34); udelay(20); /* enable chg detection */ chg_det &= ~(1 << 0); ulpi_write(phy, chg_det, 0x34); break; case SNPS_28NM_INTEGRATED_PHY: /* * Configure DM as current source, DP as current sink * and enable battery charging comparators. */ ulpi_write(phy, 0x8, 0x85); ulpi_write(phy, 0x2, 0x85); ulpi_write(phy, 0x1, 0x85); break; default: break; } }
/* drivers may have software control over D+ pullup */ static int msm72k_pullup(struct usb_gadget *_gadget, int is_active) { struct usb_info *ui = container_of(_gadget, struct usb_info, gadget); u32 cmd = (8 << 16); /* disable/enable D+ pullup */ if (is_active) { pr_info("msm_hsusb: enable pullup\n"); writel(cmd | 1, USB_USBCMD); } else { pr_info("msm_hsusb: disable pullup\n"); writel(cmd, USB_USBCMD); #if defined(CONFIG_ARCH_QSD8X50) || defined(CONFIG_ARCH_MSM7X30) ulpi_write(ui, 0x48, 0x04); #endif } return 0; }
static int ulpi_register(struct device *dev, struct ulpi *ulpi) { int ret; /* Test the interface */ ret = ulpi_write(ulpi, ULPI_SCRATCH, 0xaa); if (ret < 0) return ret; ret = ulpi_read(ulpi, ULPI_SCRATCH); if (ret < 0) return ret; if (ret != 0xaa) return -ENODEV; ulpi->id.vendor = ulpi_read(ulpi, ULPI_VENDOR_ID_LOW); ulpi->id.vendor |= ulpi_read(ulpi, ULPI_VENDOR_ID_HIGH) << 8; ulpi->id.product = ulpi_read(ulpi, ULPI_PRODUCT_ID_LOW); ulpi->id.product |= ulpi_read(ulpi, ULPI_PRODUCT_ID_HIGH) << 8; ulpi->dev.parent = dev; ulpi->dev.bus = &ulpi_bus; ulpi->dev.type = &ulpi_dev_type; dev_set_name(&ulpi->dev, "%s.ulpi", dev_name(dev)); ACPI_COMPANION_SET(&ulpi->dev, ACPI_COMPANION(dev)); request_module("ulpi:v%04xp%04x", ulpi->id.vendor, ulpi->id.product); ret = device_register(&ulpi->dev); if (ret) return ret; dev_dbg(&ulpi->dev, "registered ULPI PHY: vendor %04x, product %04x\n", ulpi->id.vendor, ulpi->id.product); return 0; }
static int msm_phy_notify_disconnect(struct usb_phy *phy, enum usb_device_speed speed) { struct msm_otg *motg = container_of(phy, struct msm_otg, phy); int val; if (motg->manual_pullup) { val = ULPI_MISC_A_VBUSVLDEXT | ULPI_MISC_A_VBUSVLDEXTSEL; usb_phy_io_write(phy, val, ULPI_CLR(ULPI_MISC_A)); } /* * Put the transceiver in non-driving mode. Otherwise host * may not detect soft-disconnection. */ val = ulpi_read(phy, ULPI_FUNC_CTRL); val &= ~ULPI_FUNC_CTRL_OPMODE_MASK; val |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING; ulpi_write(phy, val, ULPI_FUNC_CTRL); return 0; }
static void ulpi_reset(struct zynqehci_softc *sc) { uint8_t data; int timo = 1000 * 1000; /* XXXX: 1sec */ ulpi_write(sc, ULPI_FUNCTION_CONTROL + ULPI_REG_SET, FUNCTION_CONTROL_RESET /*0x20*/); do { data = ulpi_read(sc, ULPI_FUNCTION_CONTROL); if (!(data & FUNCTION_CONTROL_RESET)) break; delay(100); timo -= 100; } while (timo > 0); if (timo <= 0) { aprint_error_dev(sc->sc_hsc.sc_dev, "%s: reset failed!!\n", __func__); return; } return; }
static void disable_idgnd(struct msm_otg *dev) { ulpi_write(dev, (1<<4), 0x0F); ulpi_write(dev, (1<<4), 0x12); writel(readl(USB_OTGSC) & ~OTGSC_IDIE, USB_OTGSC); }
static void enable_idgnd(struct msm_otg *dev) { ulpi_write(dev, (1<<4), 0x0E); ulpi_write(dev, (1<<4), 0x11); writel(readl(USB_OTGSC) | OTGSC_IDIE, USB_OTGSC); }
static void disable_sess_valid(struct msm_otg *dev) { ulpi_write(dev, (1<<2), 0x0F); ulpi_write(dev, (1<<2), 0x12); writel(readl(USB_OTGSC) & ~OTGSC_BSVIE, USB_OTGSC); }
static void enable_sess_valid(struct msm_otg *dev) { ulpi_write(dev, (1<<2), 0x0E); ulpi_write(dev, (1<<2), 0x11); writel(readl(USB_OTGSC) | OTGSC_BSVIE, USB_OTGSC); }
static int msm_hsic_reset(struct msm_hsic_hcd *mehci) { struct usb_hcd *hcd = hsic_to_hcd(mehci); int ret; struct msm_hsic_host_platform_data *pdata = mehci->dev->platform_data; msm_hsic_clk_reset(mehci); /* select ulpi phy */ writel_relaxed(0x80000000, USB_PORTSC); mb(); /* HSIC init sequence when HSIC signals (Strobe/Data) are routed via GPIOs */ if (pdata && pdata->strobe && pdata->data) { /* Enable LV_MODE in HSIC_CAL_PAD_CTL register */ writel_relaxed(HSIC_LV_MODE, HSIC_CAL_PAD_CTL); mb(); /*set periodic calibration interval to ~2.048sec in HSIC_IO_CAL_REG */ ulpi_write(mehci, 0xFF, 0x33); /* Enable periodic IO calibration in HSIC_CFG register */ ulpi_write(mehci, HSIC_PAD_CALIBRATION, 0x30); /* Configure GPIO pins for HSIC functionality mode */ ret = msm_hsic_config_gpios(mehci, 1); if (ret) { dev_err(mehci->dev, " gpio configuarion failed\n"); return ret; } /* Set LV_MODE=0x1 and DCC=0x2 in HSIC_GPIO PAD_CTL register */ writel_relaxed(HSIC_GPIO_PAD_VAL, HSIC_STROBE_GPIO_PAD_CTL); writel_relaxed(HSIC_GPIO_PAD_VAL, HSIC_DATA_GPIO_PAD_CTL); mb(); /* Enable HSIC mode in HSIC_CFG register */ ulpi_write(mehci, 0x01, 0x31); } else { /* HSIC init sequence when HSIC signals (Strobe/Data) are routed via dedicated I/O */ /* programmable length of connect signaling (33.2ns) */ ret = ulpi_write(mehci, 3, HSIC_DBG1_REG); if (ret) { pr_err("%s: Unable to program length of connect " "signaling\n", __func__); } /*set periodic calibration interval to ~2.048sec in HSIC_IO_CAL_REG */ ulpi_write(mehci, 0xFF, 0x33); /* Enable HSIC mode in HSIC_CFG register */ ulpi_write(mehci, 0xA9, 0x30); } /*disable auto resume*/ ulpi_write(mehci, ULPI_IFC_CTRL_AUTORESUME, ULPI_CLR(ULPI_IFC_CTRL)); return 0; }
static void imxehci_attach(device_t parent, device_t self, void *aux) { struct imxusbc_attach_args *aa = aux; struct imxusbc_softc *usbc = device_private(parent); struct imxehci_softc *sc = device_private(self); ehci_softc_t *hsc = &sc->sc_hsc; bus_space_tag_t iot; uint16_t hcirev; usbd_status r; uint32_t id, hwhost, hwdevice; const char *comma; sc->sc_hsc.sc_dev = self; iot = sc->sc_iot = sc->sc_hsc.iot = aa->aa_iot; sc->sc_unit = aa->aa_unit; sc->sc_usbc = usbc; hsc->sc_bus.hci_private = sc; hsc->sc_flags |= EHCIF_ETTF; hsc->sc_vendor_init = imxehci_init; aprint_naive("\n"); aprint_normal(": i.MX USB Controller\n"); /* per unit registers */ if (bus_space_subregion(iot, aa->aa_ioh, aa->aa_unit * IMXUSB_EHCI_SIZE, IMXUSB_EHCI_SIZE, &sc->sc_ioh) || bus_space_subregion(iot, aa->aa_ioh, aa->aa_unit * IMXUSB_EHCI_SIZE + IMXUSB_EHCIREGS, IMXUSB_EHCI_SIZE - IMXUSB_EHCIREGS, &sc->sc_hsc.ioh)) { aprint_error_dev(self, "can't subregion\n"); return; } id = bus_space_read_4(iot, sc->sc_ioh, IMXUSB_ID); hcirev = bus_space_read_2(iot, sc->sc_hsc.ioh, EHCI_HCIVERSION); aprint_normal_dev(self, "id=%d revision=%d HCI revision=0x%x\n", (int)__SHIFTOUT(id, IMXUSB_ID_ID), (int)__SHIFTOUT(id, IMXUSB_ID_REVISION), hcirev); hwhost = bus_space_read_4(iot, sc->sc_ioh, IMXUSB_HWHOST); hwdevice = bus_space_read_4(iot, sc->sc_ioh, IMXUSB_HWDEVICE); aprint_normal_dev(self, ""); comma = ""; if (hwhost & HWHOST_HC) { int n_ports = 1 + __SHIFTOUT(hwhost, HWHOST_NPORT); aprint_normal("%d host port%s", n_ports, n_ports > 1 ? "s" : ""); comma = ", "; } if (hwdevice & HWDEVICE_DC) { int n_endpoints = __SHIFTOUT(hwdevice, HWDEVICE_DEVEP); aprint_normal("%sdevice capable, %d endpoint%s", comma, n_endpoints, n_endpoints > 1 ? "s" : ""); } aprint_normal("\n"); sc->sc_hsc.sc_bus.dmatag = aa->aa_dmat; sc->sc_hsc.sc_offs = bus_space_read_1(iot, sc->sc_hsc.ioh, EHCI_CAPLENGTH); /* Platform dependent setup */ if (usbc->sc_init_md_hook) usbc->sc_init_md_hook(sc); imxehci_reset(sc); imxehci_select_interface(sc, sc->sc_iftype); if (sc->sc_iftype == IMXUSBC_IF_ULPI) { bus_space_write_4(sc->sc_iot, sc->sc_ioh, IMXUSB_ULPIVIEW, 0); aprint_normal_dev(hsc->sc_dev, "ULPI phy VID 0x%04x PID 0x%04x\n", (imxusb_ulpi_read(sc, ULPI_VENDOR_ID_LOW) | imxusb_ulpi_read(sc, ULPI_VENDOR_ID_HIGH) << 8), (imxusb_ulpi_read(sc, ULPI_PRODUCT_ID_LOW) | imxusb_ulpi_read(sc, ULPI_PRODUCT_ID_HIGH) << 8)); ulpi_reset(sc); } if (usbc->sc_setup_md_hook) usbc->sc_setup_md_hook(sc, IMXUSB_HOST); if (sc->sc_iftype == IMXUSBC_IF_ULPI) { #if 0 if(hsc->sc_bus.usbrev == USBREV_2_0) ulpi_write(hsc, ULPI_FUNCTION_CONTROL + ULPI_REG_CLEAR, (1 << 0)); else ulpi_write(hsc, ULPI_FUNCTION_CONTROL + ULPI_REG_SET, (1 << 2)); #endif imxusb_ulpi_write(sc, ULPI_FUNCTION_CONTROL + ULPI_REG_CLEAR, OTG_CONTROL_IDPULLUP); imxusb_ulpi_write(sc, ULPI_OTG_CONTROL + ULPI_REG_SET, OTG_CONTROL_USEEXTVBUSIND | OTG_CONTROL_DRVVBUSEXT | OTG_CONTROL_DRVVBUS | OTG_CONTROL_CHRGVBUS ); } /* Disable interrupts, so we don't get any spurious ones. */ EOWRITE4(hsc, EHCI_USBINTR, 0); intr_establish(aa->aa_irq, IPL_USB, IST_LEVEL, ehci_intr, hsc); /* Figure out vendor for root hub descriptor. */ strlcpy(hsc->sc_vendor, "i.MX", sizeof(hsc->sc_vendor)); r = ehci_init(hsc); if (r != USBD_NORMAL_COMPLETION) { aprint_error_dev(self, "init failed, error=%d\n", r); return; } /* Attach usb device. */ hsc->sc_child = config_found(self, &hsc->sc_bus, usbctlprint); }
void zynqusb_attach_common(device_t parent, device_t self, bus_space_tag_t iot, bus_dma_tag_t dmat, paddr_t iobase, size_t size, int intr, int flags, enum zynq_usb_if type, enum zynq_usb_role role) { struct zynqehci_softc *sc = device_private(self); ehci_softc_t *hsc = &sc->sc_hsc; uint16_t hcirev; usbd_status r; uint32_t id, hwhost, hwdevice; const char *comma; sc->sc_hsc.sc_dev = self; sc->sc_iot = sc->sc_hsc.iot = iot; sc->sc_iftype = type; sc->sc_role = role; hsc->sc_bus.hci_private = sc; hsc->sc_bus.usbrev = USBREV_2_0; hsc->sc_flags |= EHCIF_ETTF; hsc->sc_vendor_init = zynqusb_init; aprint_normal("\n"); if (bus_space_map(iot, iobase, size, 0, &sc->sc_ioh)) { aprint_error_dev(self, "unable to map device\n"); return; } if (bus_space_subregion(iot, sc->sc_ioh, ZYNQUSB_EHCIREGS, ZYNQUSB_EHCI_SIZE - ZYNQUSB_EHCIREGS, &sc->sc_hsc.ioh)) { aprint_error_dev(self, "unable to map subregion\n"); return; } id = bus_space_read_4(iot, sc->sc_ioh, ZYNQUSB_ID); hcirev = bus_space_read_2(iot, sc->sc_hsc.ioh, EHCI_HCIVERSION); aprint_normal_dev(self, "Zynq USB Controller id=%d revision=%d version=%d\n", (int)__SHIFTOUT(id, ZYNQUSB_ID_ID), (int)__SHIFTOUT(id, ZYNQUSB_ID_REVISION), (int)__SHIFTOUT(id, ZYNQUSB_ID_VERSION)); aprint_normal_dev(self, "HCI revision=0x%x\n", hcirev); hwhost = bus_space_read_4(iot, sc->sc_ioh, ZYNQUSB_HWHOST); hwdevice = bus_space_read_4(iot, sc->sc_ioh, ZYNQUSB_HWDEVICE); aprint_normal_dev(self, ""); comma = ""; if (hwhost & HWHOST_HC) { int n_ports = 1 + __SHIFTOUT(hwhost, HWHOST_NPORT); aprint_normal("%d host port%s", n_ports, n_ports > 1 ? "s" : ""); comma = ", "; } if (hwdevice & HWDEVICE_DC) { int n_endpoints = __SHIFTOUT(hwdevice, HWDEVICE_DEVEP); aprint_normal("%sdevice capable, %d endpoint%s", comma, n_endpoints, n_endpoints > 1 ? "s" : ""); } aprint_normal("\n"); sc->sc_hsc.sc_bus.dmatag = dmat; sc->sc_hsc.sc_offs = bus_space_read_1(iot, sc->sc_hsc.ioh, EHCI_CAPLENGTH); zynqusb_reset(sc); zynqusb_select_interface(sc, sc->sc_iftype); if (sc->sc_iftype == ZYNQUSBC_IF_ULPI) { bus_space_write_4(sc->sc_iot, sc->sc_ioh, ZYNQUSB_ULPIVIEW, 0); aprint_normal_dev(hsc->sc_dev, "ULPI phy VID 0x%04x PID 0x%04x\n", (ulpi_read(sc, ULPI_VENDOR_ID_LOW) | ulpi_read(sc, ULPI_VENDOR_ID_HIGH) << 8), (ulpi_read(sc, ULPI_PRODUCT_ID_LOW) | ulpi_read(sc, ULPI_PRODUCT_ID_HIGH) << 8)); ulpi_reset(sc); } if (sc->sc_iftype == ZYNQUSBC_IF_ULPI) { if(hsc->sc_bus.usbrev == USBREV_2_0) { ulpi_write(sc, ULPI_FUNCTION_CONTROL + ULPI_REG_CLEAR, FUNCTION_CONTROL_XCVRSELECT); ulpi_write(sc, ULPI_FUNCTION_CONTROL + ULPI_REG_SET, FUNCTION_CONTROL_TERMSELECT); } else { ulpi_write(sc, ULPI_FUNCTION_CONTROL + ULPI_REG_SET, XCVRSELECT_FSLS); ulpi_write(sc, ULPI_FUNCTION_CONTROL + ULPI_REG_CLEAR, FUNCTION_CONTROL_TERMSELECT); } ulpi_write(sc, ULPI_OTG_CONTROL + ULPI_REG_SET, OTG_CONTROL_USEEXTVBUSIND | OTG_CONTROL_DRVVBUSEXT | OTG_CONTROL_DRVVBUS | OTG_CONTROL_CHRGVBUS); } /* Disable interrupts, so we don't get any spurious ones. */ EOWRITE4(hsc, EHCI_USBINTR, 0); intr_establish(intr, IPL_USB, IST_LEVEL, ehci_intr, hsc); /* Figure out vendor for root hub descriptor. */ strlcpy(hsc->sc_vendor, "Xilinx", sizeof(hsc->sc_vendor)); r = ehci_init(hsc); if (r != USBD_NORMAL_COMPLETION) { aprint_error_dev(self, "init failed, error=%d\n", r); return; } /* Attach usb device. */ hsc->sc_child = config_found(self, &hsc->sc_bus, usbctlprint); }
void target_usb_stop(void) { /* Disable VBUS mimicing in the controller. */ ulpi_write(ULPI_MISC_A_VBUSVLDEXTSEL | ULPI_MISC_A_VBUSVLDEXT, ULPI_MISC_A_CLEAR); }
static void usb_reset(struct usb_info *ui) { unsigned long flags; printk(KERN_INFO "hsusb: reset controller\n"); spin_lock_irqsave(&ui->lock, flags); ui->running = 0; spin_unlock_irqrestore(&ui->lock, flags); /* To prevent phantom packets being received by the usb core on * some devices, put the controller into reset prior to * resetting the phy. */ writel(2, USB_USBCMD); msleep(10); #if 0 /* we should flush and shutdown cleanly if already running */ writel(0xffffffff, USB_ENDPTFLUSH); msleep(2); #endif if (usb_phy_reset(ui) < 0) pr_err("%s: Phy reset failed!\n", __func__); msleep(100); /* toggle non-driving mode after phy reset to ensure that * we cause a disconnect event to the host */ ulpi_write(ui, 0x18, 0x6); msleep(1); ulpi_write(ui, 0x8, 0x5); msleep(1); /* RESET */ writel(2, USB_USBCMD); msleep(10); #ifdef CONFIG_ARCH_MSM7X00A /* INCR4 BURST mode */ writel(0x01, USB_SBUSCFG); #else /* bursts of unspecified length. */ writel(0, USB_AHBBURST); /* Use the AHB transactor */ writel(0, USB_AHBMODE); #endif /* select DEVICE mode */ writel(0x12, USB_USBMODE); msleep(1); /* select ULPI phy */ writel(0x80000000, USB_PORTSC); ulpi_init(ui); writel(ui->dma, USB_ENDPOINTLISTADDR); configure_endpoints(ui); /* marking us offline will cause ept queue attempts to fail */ ui->online = 0; /* terminate any pending transactions */ flush_all_endpoints(ui); if (ui->driver) { printk(KERN_INFO "usb: notify offline\n"); ui->driver->disconnect(&ui->gadget); } /* enable interrupts */ writel(STS_URI | STS_SLI | STS_UI | STS_PCI, USB_USBINTR); /* go to RUN mode (D+ pullup enable) */ msm72k_pullup(&ui->gadget, 1); spin_lock_irqsave(&ui->lock, flags); ui->running = 1; spin_unlock_irqrestore(&ui->lock, flags); }
static void setup_usb_phy(struct msm_ehci_priv *priv) { /* Select and enable external configuration with USB PHY */ ulpi_write(&priv->ulpi_vp, (u8 *)ULPI_MISC_A_SET, ULPI_MISC_A_VBUSVLDEXTSEL | ULPI_MISC_A_VBUSVLDEXT); }
static void usb_reset(struct usb_info *ui) { unsigned long flags; unsigned cfg_val; unsigned otgsc; INFO("msm72k_udc: reset controller\n"); spin_lock_irqsave(&ui->lock, flags); ui->running = 0; spin_unlock_irqrestore(&ui->lock, flags); #if 0 /* we should flush and shutdown cleanly if already running */ writel(0xffffffff, USB_ENDPTFLUSH); msleep(2); #endif otgsc = readl(USB_OTGSC); /* RESET */ writel(2, USB_USBCMD); msleep(10); if (ui->phy_reset) ui->phy_reset(); /* select DEVICE mode */ writel(0x12, USB_USBMODE); msleep(1); /* select ULPI phy */ writel(0x80000000, USB_PORTSC); /* electrical compliance failure in eye-diagram tests * were observed w/ integrated phy. To avoid failure * raise signal amplitude to 400mv */ cfg_val = ulpi_read(ui, ULPI_CONFIG_REG); cfg_val |= ULPI_AMPLITUDE_MAX; ulpi_write(ui, cfg_val, ULPI_CONFIG_REG); /* fix potential usb stability issues with "integrated phy" * by enabling unspecified length of INCR burst and using * the AHB master interface of the AHB2AHB transactor */ writel(0, USB_AHB_BURST); writel(0, USB_AHB_MODE); ulpi_init(ui); writel(ui->dma, USB_ENDPOINTLISTADDR); configure_endpoints(ui); /* marking us offline will cause ept queue attempts to fail */ ui->online = 0; /* terminate any pending transactions */ flush_all_endpoints(ui); if (ui->driver) { printk(KERN_INFO "usb: notify offline\n"); ui->driver->disconnect(&ui->gadget); } /* enable interrupts */ writel(otgsc, USB_OTGSC); writel(STS_URI | STS_SLI | STS_UI | STS_PCI, USB_USBINTR); spin_lock_irqsave(&ui->lock, flags); ui->running = 1; spin_unlock_irqrestore(&ui->lock, flags); }
static int msm_otg_suspend(struct msm_otg *motg) { struct usb_phy *phy = &motg->phy; struct usb_bus *bus = phy->otg->host; struct msm_otg_platform_data *pdata = motg->pdata; void __iomem *addr; int cnt = 0; if (atomic_read(&motg->in_lpm)) return 0; disable_irq(motg->irq); /* * Chipidea 45-nm PHY suspend sequence: * * Interrupt Latch Register auto-clear feature is not present * in all PHY versions. Latch register is clear on read type. * Clear latch register to avoid spurious wakeup from * low power mode (LPM). * * PHY comparators are disabled when PHY enters into low power * mode (LPM). Keep PHY comparators ON in LPM only when we expect * VBUS/Id notifications from USB PHY. Otherwise turn off USB * PHY comparators. This save significant amount of power. * * PLL is not turned off when PHY enters into low power mode (LPM). * Disable PLL for maximum power savings. */ if (motg->pdata->phy_type == CI_45NM_INTEGRATED_PHY) { ulpi_read(phy, 0x14); if (pdata->otg_control == OTG_PHY_CONTROL) ulpi_write(phy, 0x01, 0x30); ulpi_write(phy, 0x08, 0x09); } /* * PHY may take some time or even fail to enter into low power * mode (LPM). Hence poll for 500 msec and reset the PHY and link * in failure case. */ writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC); while (cnt < PHY_SUSPEND_TIMEOUT_USEC) { if (readl(USB_PORTSC) & PORTSC_PHCD) break; udelay(1); cnt++; } if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) { dev_err(phy->dev, "Unable to suspend PHY\n"); msm_otg_reset(phy); enable_irq(motg->irq); return -ETIMEDOUT; } /* * PHY has capability to generate interrupt asynchronously in low * power mode (LPM). This interrupt is level triggered. So USB IRQ * line must be disabled till async interrupt enable bit is cleared * in USBCMD register. Assert STP (ULPI interface STOP signal) to * block data communication from PHY. */ writel(readl(USB_USBCMD) | ASYNC_INTR_CTRL | ULPI_STP_CTRL, USB_USBCMD); addr = USB_PHY_CTRL; if (motg->phy_number) addr = USB_PHY_CTRL2; if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY && motg->pdata->otg_control == OTG_PMIC_CONTROL) writel(readl(addr) | PHY_RETEN, addr); clk_disable_unprepare(motg->pclk); clk_disable_unprepare(motg->clk); if (!IS_ERR(motg->core_clk)) clk_disable_unprepare(motg->core_clk); if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY && motg->pdata->otg_control == OTG_PMIC_CONTROL) { msm_hsusb_ldo_set_mode(motg, 0); msm_hsusb_config_vddcx(motg, 0); } if (device_may_wakeup(phy->dev)) enable_irq_wake(motg->irq); if (bus) clear_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags); atomic_set(&motg->in_lpm, 1); enable_irq(motg->irq); dev_info(phy->dev, "USB in low power mode\n"); return 0; }
static void reset_usb_phy(struct msm_ehci_priv *priv) { /* Disable VBUS mimicing in the controller. */ ulpi_write(&priv->ulpi_vp, (u8 *)ULPI_MISC_A_CLEAR, ULPI_MISC_A_VBUSVLDEXTSEL | ULPI_MISC_A_VBUSVLDEXT); }
static int qcom_usb_hs_phy_power_on(struct phy *phy) { struct qcom_usb_hs_phy *uphy = phy_get_drvdata(phy); struct ulpi *ulpi = uphy->ulpi; const struct ulpi_seq *seq; int ret, state; ret = clk_prepare_enable(uphy->ref_clk); if (ret) return ret; ret = clk_prepare_enable(uphy->sleep_clk); if (ret) goto err_sleep; ret = regulator_set_load(uphy->v1p8, 50000); if (ret < 0) goto err_1p8; ret = regulator_enable(uphy->v1p8); if (ret) goto err_1p8; ret = regulator_set_voltage_triplet(uphy->v3p3, 3050000, 3300000, 3300000); if (ret) goto err_3p3; ret = regulator_set_load(uphy->v3p3, 50000); if (ret < 0) goto err_3p3; ret = regulator_enable(uphy->v3p3); if (ret) goto err_3p3; for (seq = uphy->init_seq; seq->addr; seq++) { ret = ulpi_write(ulpi, ULPI_EXT_VENDOR_SPECIFIC + seq->addr, seq->val); if (ret) goto err_ulpi; } if (uphy->reset) { ret = reset_control_reset(uphy->reset); if (ret) goto err_ulpi; } if (uphy->vbus_edev) { state = extcon_get_state(uphy->vbus_edev, EXTCON_USB); /* setup initial state */ qcom_usb_hs_phy_vbus_notifier(&uphy->vbus_notify, state, uphy->vbus_edev); ret = devm_extcon_register_notifier(&ulpi->dev, uphy->vbus_edev, EXTCON_USB, &uphy->vbus_notify); if (ret) goto err_ulpi; } return 0; err_ulpi: regulator_disable(uphy->v3p3); err_3p3: regulator_disable(uphy->v1p8); err_1p8: clk_disable_unprepare(uphy->sleep_clk); err_sleep: clk_disable_unprepare(uphy->ref_clk); return ret; }
static int msm_otg_suspend(struct msm_otg *dev) { unsigned long timeout; int vbus = 0; unsigned otgsc; disable_irq(dev->irq); if (dev->in_lpm) goto out; /* Don't reset if mini-A cable is connected */ if (!is_host()) otg_reset(dev); /* In case of fast plug-in and plug-out inside the otg_reset() the * servicing of BSV is missed (in the window of after phy and link * reset). Handle it if any missing bsv is detected */ if (is_b_sess_vld() && !is_host()) { otgsc = readl(USB_OTGSC); writel(otgsc, USB_OTGSC); pr_info("%s:Process mising BSV\n", __func__); msm_otg_start_peripheral(&dev->otg, 1); enable_irq(dev->irq); return -1; } ulpi_read(dev, 0x14);/* clear PHY interrupt latch register */ /* If there is no pmic notify support turn on phy comparators. */ if (!dev->pmic_notif_supp) ulpi_write(dev, 0x01, 0x30); ulpi_write(dev, 0x08, 0x09);/* turn off PLL on integrated phy */ timeout = jiffies + msecs_to_jiffies(500); disable_phy_clk(); while (!is_phy_clk_disabled()) { if (time_after(jiffies, timeout)) { pr_err("%s: Unable to suspend phy\n", __func__); otg_reset(dev); goto out; } msleep(1); } writel(readl(USB_USBCMD) | ASYNC_INTR_CTRL | ULPI_STP_CTRL, USB_USBCMD); clk_disable(dev->pclk); if (dev->cclk) clk_disable(dev->cclk); if (device_may_wakeup(dev->otg.dev)) { enable_irq_wake(dev->irq); if (dev->vbus_on_irq) enable_irq_wake(dev->vbus_on_irq); } dev->in_lpm = 1; if (!vbus && dev->pmic_notif_supp) dev->pmic_enable_ldo(0); pr_info("%s: usb in low power mode\n", __func__); out: enable_irq(dev->irq); /* TBD: as there is no bus suspend implemented as of now * it should be dummy check */ return 0; }