static int ulpi_init(struct usb_phy *phy) { int i, vid, pid, ret; u32 ulpi_id = 0; for (i = 0; i < 4; i++) { ret = usb_phy_io_read(phy, ULPI_PRODUCT_ID_HIGH - i); if (ret < 0) return ret; ulpi_id = (ulpi_id << 8) | ret; } vid = ulpi_id & 0xffff; pid = ulpi_id >> 16; pr_info("ULPI transceiver vendor/product ID 0x%04x/0x%04x\n", vid, pid); for (i = 0; i < ARRAY_SIZE(ulpi_ids); i++) { if (ulpi_ids[i].id == ULPI_ID(vid, pid)) { pr_info("Found %s ULPI transceiver.\n", ulpi_ids[i].name); break; } } ret = ulpi_check_integrity(phy); if (ret) return ret; return ulpi_set_flags(phy); }
static int ulpi_set_host(struct usb_otg *otg, struct usb_bus *host) { struct usb_phy *phy = otg->phy; unsigned int flags = usb_phy_io_read(phy, ULPI_IFC_CTRL); if (!host) { otg->host = NULL; return 0; } otg->host = host; flags &= ~(ULPI_IFC_CTRL_6_PIN_SERIAL_MODE | ULPI_IFC_CTRL_3_PIN_SERIAL_MODE | ULPI_IFC_CTRL_CARKITMODE); if (phy->flags & ULPI_IC_6PIN_SERIAL) flags |= ULPI_IFC_CTRL_6_PIN_SERIAL_MODE; else if (phy->flags & ULPI_IC_3PIN_SERIAL) flags |= ULPI_IFC_CTRL_3_PIN_SERIAL_MODE; else if (phy->flags & ULPI_IC_CARKIT) flags |= ULPI_IFC_CTRL_CARKITMODE; return usb_phy_io_write(phy, flags, ULPI_IFC_CTRL); }
static void ci13xxx_msm_notify_event(struct ci13xxx *ci, unsigned event) { struct device *dev = ci->gadget.dev.parent; int val; switch (event) { case CI13XXX_CONTROLLER_RESET_EVENT: dev_dbg(dev, "CI13XXX_CONTROLLER_RESET_EVENT received\n"); writel(0, USB_AHBBURST); writel(0, USB_AHBMODE); break; case CI13XXX_CONTROLLER_STOPPED_EVENT: dev_dbg(dev, "CI13XXX_CONTROLLER_STOPPED_EVENT received\n"); /* * Put the transceiver in non-driving mode. Otherwise host * may not detect soft-disconnection. */ val = usb_phy_io_read(ci->transceiver, ULPI_FUNC_CTRL); val &= ~ULPI_FUNC_CTRL_OPMODE_MASK; val |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING; usb_phy_io_write(ci->transceiver, val, ULPI_FUNC_CTRL); break; default: dev_dbg(dev, "unknown ci13xxx event\n"); break; } }
static int ulpi_check_integrity(struct usb_phy *phy) { int ret, i; unsigned int val = 0x55; for (i = 0; i < 2; i++) { ret = usb_phy_io_write(phy, val, ULPI_SCRATCH); if (ret < 0) return ret; ret = usb_phy_io_read(phy, ULPI_SCRATCH); if (ret < 0) return ret; if (ret != val) { pr_err("ULPI integrity check: failed!"); return -ENODEV; } val = val << 1; } pr_info("ULPI integrity check: passed.\n"); return 0; }
static int ulpi_set_vbus(struct usb_otg *otg, bool on) { struct usb_phy *phy = otg->phy; unsigned int flags = usb_phy_io_read(phy, ULPI_OTG_CTRL); flags &= ~(ULPI_OTG_CTRL_DRVVBUS | ULPI_OTG_CTRL_DRVVBUS_EXT); if (on) { if (phy->flags & ULPI_OTG_DRVVBUS) flags |= ULPI_OTG_CTRL_DRVVBUS; if (phy->flags & ULPI_OTG_DRVVBUS_EXT) flags |= ULPI_OTG_CTRL_DRVVBUS_EXT; } return usb_phy_io_write(phy, flags, ULPI_OTG_CTRL); }
/** * dwc3_core_init - Low-level initialization of DWC3 Core * @dwc: Pointer to our controller context structure * * Returns 0 on success otherwise negative errno. */ static int dwc3_core_init(struct dwc3 *dwc) { unsigned long timeout; u32 reg; int ret; struct usb_phy *usb_phy; reg = dwc3_readl(dwc->regs, DWC3_GSNPSID); /* This should read as U3 followed by revision number */ if ((reg & DWC3_GSNPSID_MASK) != 0x55330000) { dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n"); ret = -ENODEV; goto err0; } dwc->revision = reg; /* issue device SoftReset too */ timeout = jiffies + msecs_to_jiffies(500); dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST); do { reg = dwc3_readl(dwc->regs, DWC3_DCTL); if (!(reg & DWC3_DCTL_CSFTRST)) break; if (time_after(jiffies, timeout)) { dev_err(dwc->dev, "Reset Timed Out\n"); ret = -ETIMEDOUT; goto err0; } cpu_relax(); } while (true); dwc3_core_soft_reset(dwc); /* DCTL core soft reset may cause PHY hang, delay 1 ms and check ulpi */ mdelay(1); if (!dwc->utmi_phy) { usb_phy = usb_get_phy(USB_PHY_TYPE_USB2); if (usb_phy && usb_phy_io_read(usb_phy, ULPI_VENDOR_ID_LOW) < 0) dev_err(dwc->dev, "ULPI not working after DCTL soft reset\n"); usb_put_phy(usb_phy); } reg = dwc3_readl(dwc->regs, DWC3_GCTL); reg &= ~DWC3_GCTL_SCALEDOWN_MASK; reg &= ~DWC3_GCTL_DISSCRAMBLE; switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) { case DWC3_GHWPARAMS1_EN_PWROPT_CLK: reg &= ~DWC3_GCTL_DSBLCLKGTNG; break; default: dev_dbg(dwc->dev, "No power optimization available\n"); } /* * WORKAROUND: DWC3 revisions <1.90a have a bug * where the device can fail to connect at SuperSpeed * and falls back to high-speed mode which causes * the device to enter a Connect/Disconnect loop */ if (dwc->revision < DWC3_REVISION_190A) reg |= DWC3_GCTL_U2RSTECN; dwc3_core_num_eps(dwc); dwc3_writel(dwc->regs, DWC3_GCTL, reg); return 0; err0: return ret; }
static inline int isp1704_read(struct isp1704_charger *isp, u32 reg) { return usb_phy_io_read(isp->phy, reg); }
static enum power_supply_charger_cable_type dwc3_intel_byt_get_charger_type(struct dwc_otg2 *otg) { struct usb_phy *phy; u8 val, vdat_det, chgd_serx_dm; unsigned long timeout, interval; enum power_supply_charger_cable_type type = POWER_SUPPLY_CHARGER_TYPE_NONE; /* No need to do charger detection if not enabled */ if (!charger_detect_enable(otg)) return POWER_SUPPLY_CHARGER_TYPE_USB_SDP; phy = usb_get_phy(USB_PHY_TYPE_USB2); if (!phy) { otg_err(otg, "Get USB2 PHY failed\n"); return POWER_SUPPLY_CHARGER_TYPE_NONE; } /* PHY Enable: * Power on PHY */ enable_usb_phy(otg, true); /* Wait 10ms (~5ms before PHY de-asserts DIR, * XXus for initial Link reg sync-up).*/ msleep(20); /* DCD Enable: Change OPMODE to 01 (Non-driving), * TermSel to 0, & * XcvrSel to 01 (enable FS xcvr) */ usb_phy_io_write(phy, FUNCCTRL_OPMODE(1) | FUNCCTRL_XCVRSELECT(1), TUSB1211_FUNC_CTRL_SET); usb_phy_io_write(phy, FUNCCTRL_OPMODE(2) | FUNCCTRL_XCVRSELECT(2) | FUNCCTRL_TERMSELECT, TUSB1211_FUNC_CTRL_CLR); /*Enable SW control*/ usb_phy_io_write(phy, PWCTRL_SW_CONTROL, TUSB1211_POWER_CONTROL_SET); /* Enable IDPSRC */ usb_phy_io_write(phy, VS3_CHGD_IDP_SRC_EN, TUSB1211_VENDOR_SPECIFIC3_SET); /* Check DCD result, use same polling parameter */ timeout = jiffies + msecs_to_jiffies(DATACON_TIMEOUT); interval = DATACON_INTERVAL * 1000; /* us */ /* DCD Check: * Delay 66.5 ms. (Note: * TIDP_SRC_ON + TCHGD_SERX_DEB = * 347.8us + 66.1ms). */ usleep_range(66500, 67000); while (!time_after(jiffies, timeout)) { /* Read DP logic level. */ val = usb_phy_io_read(phy, TUSB1211_VENDOR_SPECIFIC4); if (val < 0) { otg_err(otg, "ULPI read error! try again\n"); continue; } if (!(val & VS4_CHGD_SERX_DP)) { otg_info(otg, "Data contact detected!\n"); break; } /* Polling interval */ usleep_range(interval, interval + 2000); } /* Disable DP pullup (Idp_src) */ usb_phy_io_write(phy, VS3_CHGD_IDP_SRC_EN, TUSB1211_VENDOR_SPECIFIC3_CLR); /* SE1 Det Enable: * Read DP/DM logic level. Note: use DEBUG * because VS4 isn’t enabled in this situation. */ val = usb_phy_io_read(phy, TUSB1211_DEBUG); if (val < 0) otg_err(otg, "ULPI read error!\n"); val &= DEBUG_LINESTATE; /* If '11': SE1 detected; goto 'Cleanup'. * Else: goto 'Pri Det Enable'. */ if (val == 3) { type = POWER_SUPPLY_CHARGER_TYPE_SE1; goto cleanup; } /* Pri Det Enable: * Enable VDPSRC. */ usb_phy_io_write(phy, PWCTRL_DP_VSRC_EN, TUSB1211_POWER_CONTROL_SET); /* Wait >106.1ms (40ms for BC * Tvdpsrc_on, 66.1ms for TI CHGD_SERX_DEB). */ msleep(107); /* Pri Det Check: * Check if DM > VDATREF. */ vdat_det = usb_phy_io_read(phy, TUSB1211_POWER_CONTROL); if (vdat_det < 0) otg_err(otg, "ULPI read error!\n"); vdat_det &= PWCTRL_VDAT_DET; /* Check if DM<VLGC */ chgd_serx_dm = usb_phy_io_read(phy, TUSB1211_VENDOR_SPECIFIC4); if (chgd_serx_dm < 0) otg_err(otg, "ULPI read error!\n"); chgd_serx_dm &= VS4_CHGD_SERX_DM; /* If VDAT_DET==0 || CHGD_SERX_DM==1: SDP detected * If VDAT_DET==1 && CHGD_SERX_DM==0: CDP/DCP */ if (vdat_det == 0 || chgd_serx_dm == 1) type = POWER_SUPPLY_CHARGER_TYPE_USB_SDP; /* Disable VDPSRC. */ usb_phy_io_write(phy, PWCTRL_DP_VSRC_EN, TUSB1211_POWER_CONTROL_CLR); /* If SDP, goto “Cleanup”. * Else, goto “Sec Det Enable” */ if (type == POWER_SUPPLY_CHARGER_TYPE_USB_SDP) goto cleanup; /* Sec Det Enable: * delay 1ms. */ usleep_range(1000, 1500); /* Swap DP & DM */ usb_phy_io_write(phy, VS1_DATAPOLARITY, TUSB1211_VENDOR_SPECIFIC1_CLR); /* Enable 'VDMSRC'. */ usb_phy_io_write(phy, PWCTRL_DP_VSRC_EN, TUSB1211_POWER_CONTROL_SET); /* Wait >73ms (40ms for BC Tvdmsrc_on, 33ms for TI TVDPSRC_DEB) */ msleep(80); /* Sec Det Check: * Check if DP>VDATREF. */ val = usb_phy_io_read(phy, TUSB1211_POWER_CONTROL); if (val < 0) otg_err(otg, "ULPI read error!\n"); val &= PWCTRL_VDAT_DET; /* If VDAT_DET==0: CDP detected. * If VDAT_DET==1: DCP detected. */ if (!val) type = POWER_SUPPLY_CHARGER_TYPE_USB_CDP; else type = POWER_SUPPLY_CHARGER_TYPE_USB_DCP; /* Disable VDMSRC. */ usb_phy_io_write(phy, PWCTRL_DP_VSRC_EN, TUSB1211_POWER_CONTROL_CLR); /* Swap DP & DM. */ usb_phy_io_write(phy, VS1_DATAPOLARITY, TUSB1211_VENDOR_SPECIFIC1_SET); cleanup: /* If DCP detected, assert VDPSRC. */ if (type == POWER_SUPPLY_CHARGER_TYPE_USB_DCP) usb_phy_io_write(phy, PWCTRL_SW_CONTROL | PWCTRL_DP_VSRC_EN, TUSB1211_POWER_CONTROL_SET); usb_put_phy(phy); switch (type) { case POWER_SUPPLY_CHARGER_TYPE_ACA_DOCK: case POWER_SUPPLY_CHARGER_TYPE_ACA_A: case POWER_SUPPLY_CHARGER_TYPE_ACA_B: case POWER_SUPPLY_CHARGER_TYPE_ACA_C: case POWER_SUPPLY_CHARGER_TYPE_USB_DCP: case POWER_SUPPLY_CHARGER_TYPE_USB_CDP: case POWER_SUPPLY_CHARGER_TYPE_SE1: dwc_otg_charger_hwdet(true); break; default: break; }; return type; }
static int ehci_mxc_drv_probe(struct platform_device *pdev) { struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data; struct usb_hcd *hcd; struct resource *res; int irq, ret; unsigned int flags; struct ehci_mxc_priv *priv; struct device *dev = &pdev->dev; struct ehci_hcd *ehci; dev_info(&pdev->dev, "initializing i.MX USB Controller\n"); if (!pdata) { dev_err(dev, "No platform data given, bailing out.\n"); return -EINVAL; } irq = platform_get_irq(pdev, 0); hcd = usb_create_hcd(&ehci_mxc_hc_driver, dev, dev_name(dev)); if (!hcd) return -ENOMEM; priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) { ret = -ENOMEM; goto err_alloc; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(dev, "Found HC with no register addr. Check setup!\n"); ret = -ENODEV; goto err_get_resource; } hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { dev_dbg(dev, "controller already in use\n"); ret = -EBUSY; goto err_request_mem; } hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); if (!hcd->regs) { dev_err(dev, "error mapping memory\n"); ret = -EFAULT; goto err_ioremap; } priv->usbclk = clk_get(dev, "usb"); if (IS_ERR(priv->usbclk)) { ret = PTR_ERR(priv->usbclk); goto err_clk; } clk_enable(priv->usbclk); if (!cpu_is_mx35() && !cpu_is_mx25()) { priv->ahbclk = clk_get(dev, "usb_ahb"); if (IS_ERR(priv->ahbclk)) { ret = PTR_ERR(priv->ahbclk); goto err_clk_ahb; } clk_enable(priv->ahbclk); } if (cpu_is_mx51() && (pdev->id == 0)) { priv->phy1clk = clk_get(dev, "usb_phy1"); if (IS_ERR(priv->phy1clk)) { ret = PTR_ERR(priv->phy1clk); goto err_clk_phy; } clk_enable(priv->phy1clk); } if (pdata->init) { ret = pdata->init(pdev); if (ret) { dev_err(dev, "platform init failed\n"); goto err_init; } mdelay(10); } ehci = hcd_to_ehci(hcd); ehci->caps = hcd->regs + 0x100; ehci->regs = hcd->regs + 0x100 + HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase)); ehci_writel(ehci, pdata->portsc, &ehci->regs->port_status[0]); msleep(10); if (pdata->otg) { pdata->otg->io_priv = hcd->regs + ULPI_VIEWPORT_OFFSET; ret = usb_phy_init(pdata->otg); if (ret) { dev_err(dev, "unable to init transceiver, probably missing\n"); ret = -ENODEV; goto err_add; } ret = otg_set_vbus(pdata->otg->otg, 1); if (ret) { dev_err(dev, "unable to enable vbus on transceiver\n"); goto err_add; } } priv->hcd = hcd; platform_set_drvdata(pdev, priv); ret = usb_add_hcd(hcd, irq, IRQF_SHARED); if (ret) goto err_add; if (pdata->otg) { if (machine_is_mx51_efikamx() || machine_is_mx51_efikasb()) { flags = usb_phy_io_read(pdata->otg, ULPI_OTG_CTRL); flags |= ULPI_OTG_CTRL_CHRGVBUS; ret = usb_phy_io_write(pdata->otg, flags, ULPI_OTG_CTRL); if (ret) { dev_err(dev, "unable to set CHRVBUS\n"); goto err_add; } } } return 0; err_add: if (pdata && pdata->exit) pdata->exit(pdev); err_init: if (priv->phy1clk) { clk_disable(priv->phy1clk); clk_put(priv->phy1clk); } err_clk_phy: if (priv->ahbclk) { clk_disable(priv->ahbclk); clk_put(priv->ahbclk); } err_clk_ahb: clk_disable(priv->usbclk); clk_put(priv->usbclk); err_clk: iounmap(hcd->regs); err_ioremap: release_mem_region(hcd->rsrc_start, hcd->rsrc_len); err_request_mem: err_get_resource: kfree(priv); err_alloc: usb_put_hcd(hcd); return ret; }
int dwc3_intel_suspend(struct dwc_otg2 *otg) { int ret; struct usb_phy *phy; struct pci_dev *pci_dev; struct usb_hcd *hcd = NULL; pci_power_t state = PCI_D3cold; if (!otg) return 0; hcd = container_of(otg->otg.host, struct usb_hcd, self); pci_dev = to_pci_dev(otg->dev); if (otg->state == DWC_STATE_A_HOST && otg->suspend_host) { /* Check if USB2 ULPI PHY is hang via access its internal * registers. If hang, then do hard reset before enter * hibernation mode. Otherwise, the USB2 PHY can't enter * suspended state which will blocking U2PMU can't get ready * then can't enter D0i3hot forever in SCU FW. */ if (!is_utmi_phy(otg)) { phy = usb_get_phy(USB_PHY_TYPE_USB2); if (!phy) return -ENODEV; if (usb_phy_io_read(phy, ULPI_VENDOR_ID_LOW) < 0) { enable_usb_phy(otg, 0); enable_usb_phy(otg, 1); } usb_put_phy(phy); } ret = otg->suspend_host(hcd); if (ret) { otg_err(otg, "dwc3-host enter suspend faield: %d\n", ret); return ret; } } if (otg->state == DWC_STATE_B_PERIPHERAL || otg->state == DWC_STATE_A_HOST) state = PCI_D3hot; set_sus_phy(otg, 1); if (pci_save_state(pci_dev)) { otg_err(otg, "pci_save_state failed!\n"); return -EIO; } pci_disable_device(pci_dev); if ((state == PCI_D3cold) && is_utmi_phy(otg)) { /* Important!! Whenever the VUSBPHY rail is disabled, SW * must assert USBRST# to isolate the SOC’s DP/DM pins from the * outside world. There is a risk of damage to the SOC if a * peripheral were to bias DP/DM to 3.3V when the SOC is * unpowered. */ ret = intel_scu_ipc_update_register(PMIC_USBPHYCTRL, 0x0, USBPHYRSTB); if (ret) otg_err(otg, "%s: ipc update failed\n", __func__); } pci_set_power_state(pci_dev, state); return 0; }