staticint ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable)
{ struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct ehci_ci_priv *priv = (struct ehci_ci_priv *)ehci->priv; struct device *dev = hcd->self.controller; struct ci_hdrc *ci = dev_get_drvdata(dev); int ret = 0; int port = HCS_N_PORTS(ehci->hcs_params);
if (priv->reg_vbus && enable != priv->enabled) { if (port > 1) {
dev_warn(dev, "Not support multi-port regulator control\n"); return 0;
} if (enable)
ret = regulator_enable(priv->reg_vbus); else
ret = regulator_disable(priv->reg_vbus); if (ret) {
dev_err(dev, "Failed to %s vbus regulator, ret=%d\n",
str_enable_disable(enable), ret); return ret;
}
priv->enabled = enable;
}
if (ci->platdata->flags & CI_HDRC_PHY_VBUS_CONTROL) { if (enable)
usb_phy_vbus_on(ci->usb_phy); else
usb_phy_vbus_off(ci->usb_phy);
}
if (enable && (ci->platdata->phy_mode == USBPHY_INTERFACE_MODE_HSIC)) { /* * Marvell 28nm HSIC PHY requires forcing the port to HS mode. * As HSIC is always HS, this should be safe for others.
*/
hw_port_test_set(ci, 5);
hw_port_test_set(ci, 0);
} return 0;
};
/* * Avoid out-of-bounds values while calculating the port index * from wIndex. The compiler doesn't like pointers to invalid * addresses, even if they are never used.
*/
port_index = (wIndex - 1) & 0xff; if (port_index >= HCS_N_PORTS_MAX)
port_index = 0;
status_reg = &ehci->regs->port_status[port_index];
spin_lock_irqsave(&ehci->lock, flags);
if (ci->platdata->hub_control) {
retval = ci->platdata->hub_control(ci, typeReq, wValue, wIndex,
buf, wLength, &done, &flags); if (done) goto done;
}
/* * If a transaction is in progress, there may be a delay in * suspending the port. Poll until the port is suspended.
*/ if (ehci_handshake(ehci, status_reg, PORT_SUSPEND,
PORT_SUSPEND, 5000))
ehci_err(ehci, "timeout waiting for SUSPEND\n");
if (ci->platdata->flags & CI_HDRC_IMX_IS_HSIC) { if (ci->platdata->notify_event)
ci->platdata->notify_event(ci,
CI_HDRC_IMX_HSIC_SUSPEND_EVENT);
/* * After resume has finished, it needs do some post resume * operation for some SoCs.
*/ elseif (typeReq == ClearPortFeature &&
wValue == USB_PORT_FEAT_C_SUSPEND) { /* Make sure the resume has finished, it should be finished */ if (ehci_handshake(ehci, status_reg, PORT_RESUME, 0, 25000))
ehci_err(ehci, "timeout waiting for resume\n");
}
port = HCS_N_PORTS(ehci->hcs_params); while (port--) {
u32 __iomem *reg = &ehci->regs->port_status[port];
u32 portsc = ehci_readl(ehci, reg);
if (portsc & PORT_CONNECT) { /* * For chipidea, the resume signal will be ended * automatically, so for remote wakeup case, the * usbcmd.rs may not be set before the resume has * ended if other resume paths consumes too much * time (~24ms), in that case, the SOF will not * send out within 3ms after resume ends, then the * high speed device will enter full speed mode.
*/
tmp = ehci_readl(ehci, &ehci->regs->command);
tmp |= CMD_RUN;
ehci_writel(ehci, tmp, &ehci->regs->command); /* * It needs a short delay between set RS bit and PHCD.
*/
usleep_range(150, 200); /* * Need to clear WKCN and WKOC for imx HSIC, * otherwise, there will be wakeup event.
*/ if (ci->platdata->flags & CI_HDRC_IMX_IS_HSIC) {
tmp = ehci_readl(ehci, reg);
tmp &= ~(PORT_WKDISC_E | PORT_WKCONN_E);
ehci_writel(ehci, tmp, reg);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.