usb: ehci: pass full speed devices to companion controller
According to the "Enhanced Host Controller Interface Specification for Universal Serial Bus" after a USB port reset the EHCI Driver checks the PortEnable bit in the PORTSC register. If set to a one, the connected device is a high-speed device [...]. At the time the EHCI Driver receives the port reset and enable request the LineStatus bits might indicate a low-speed device. Additionally, when the port reset process is complete, the PortEnable field may indicate that a full-speed device is attached. In either case the EHCI driver sets the PortOwner bit in the PORTSC register to a one to release port ownership to a companion host controller. Signed-off-by: Peter Mamonov <pmamonov@gmail.com> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
This commit is contained in:
parent
db791c7fb2
commit
6d205422e5
|
@ -476,6 +476,18 @@ static inline void ehci_powerup_fixup(struct ehci_priv *ehci)
|
|||
}
|
||||
#endif
|
||||
|
||||
static void pass_to_companion(struct ehci_priv *ehci, int port)
|
||||
{
|
||||
uint32_t *status_reg = (uint32_t *)&ehci->hcor->or_portsc[port - 1];
|
||||
uint32_t reg = ehci_readl(status_reg);
|
||||
|
||||
reg &= ~EHCI_PS_CLEAR;
|
||||
dev_dbg(ehci->dev, "port %d --> companion\n",
|
||||
port - 1);
|
||||
reg |= EHCI_PS_PO;
|
||||
ehci_writel(status_reg, reg);
|
||||
}
|
||||
|
||||
static int
|
||||
ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
|
||||
int length, struct devrequest *req)
|
||||
|
@ -508,6 +520,10 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
|
|||
return -1;
|
||||
}
|
||||
status_reg = (uint32_t *)&ehci->hcor->or_portsc[port - 1];
|
||||
if (ehci_readl(status_reg) & EHCI_PS_PO) {
|
||||
dev_dbg(ehci->dev, "Port %d is owned by companion controller\n", port);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
status_reg = NULL;
|
||||
|
@ -654,11 +670,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
|
|||
if ((reg & (EHCI_PS_PE | EHCI_PS_CS)) == EHCI_PS_CS &&
|
||||
!ehci_is_TDI() &&
|
||||
EHCI_PS_IS_LOWSPEED(reg)) {
|
||||
/* Low speed device, give up ownership. */
|
||||
dev_dbg(ehci->dev, "port %d low speed --> companion\n",
|
||||
port - 1);
|
||||
reg |= EHCI_PS_PO;
|
||||
ehci_writel(status_reg, reg);
|
||||
pass_to_companion(ehci, port);
|
||||
break;
|
||||
} else {
|
||||
int ret;
|
||||
|
@ -689,7 +701,10 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
|
|||
else
|
||||
dev_err(ehci->dev, "port(%d) reset error\n",
|
||||
port - 1);
|
||||
|
||||
mdelay(200);
|
||||
reg = ehci_readl(status_reg);
|
||||
if (!(reg & EHCI_PS_PE))
|
||||
pass_to_companion(ehci, port);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
Loading…
Reference in New Issue