On Wed, Feb 15, 2012 at 06:56:59PM -0800, Paul Zimmerman wrote: return -ENOCOMMITLOG please add something here. This is quite big patch ;-) some small explanation of what has changed starting on version XYZ would be cool. > Signed-off-by: Paul Zimmerman <paulz@xxxxxxxxxxxx> > --- > drivers/usb/dwc3/gadget.c | 105 ++++++++++++++++++++++++++++++++++---------- > 1 files changed, 81 insertions(+), 24 deletions(-) > > diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c > index 3b0ec64..af71994 100644 > --- a/drivers/usb/dwc3/gadget.c > +++ b/drivers/usb/dwc3/gadget.c > @@ -100,6 +100,23 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state) > int retries = 10000; > u32 reg; > > + /* > + * Wait until device controller is ready. Only applies to 1.94a and > + * later RTL. > + */ > + if (dwc->revision >= DWC3_REVISION_194A) { > + while (--retries) { > + reg = dwc3_readl(dwc->regs, DWC3_DSTS); > + if (reg & DWC3_DSTS_DCNRD) > + udelay(5); > + else > + break; > + } > + > + if (retries <= 0) > + return -ETIMEDOUT; > + } > + > reg = dwc3_readl(dwc->regs, DWC3_DCTL); > reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK; > > @@ -107,7 +124,15 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state) > reg |= DWC3_DCTL_ULSTCHNGREQ(state); > dwc3_writel(dwc->regs, DWC3_DCTL, reg); > > + /* > + * The following code is racy when called from dwc3_gadget_wakeup, > + * and is not needed, at least on newer versions > + */ > + if (dwc->revision >= DWC3_REVISION_194A) > + return 0; > + > /* wait for a change in DSTS */ > + retries = 10000; > while (--retries) { > reg = dwc3_readl(dwc->regs, DWC3_DSTS); > > @@ -265,8 +290,8 @@ static const char *dwc3_gadget_ep_cmd_string(u8 cmd) > return "Clear Stall"; > case DWC3_DEPCMD_SETSTALL: > return "Set Stall"; > - case DWC3_DEPCMD_GETSEQNUMBER: > - return "Get Data Sequence Number"; > + case DWC3_DEPCMD_GETEPSTATE: > + return "Get Endpoint State"; > case DWC3_DEPCMD_SETTRANSFRESOURCE: > return "Set Endpoint Transfer Resource"; > case DWC3_DEPCMD_SETEPCONFIG: > @@ -1234,9 +1259,12 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) > goto out; > } > > - /* write zeroes to Link Change Request */ > - reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK; > - dwc3_writel(dwc->regs, DWC3_DCTL, reg); > + /* Recent versions do this automatically */ > + if (dwc->revision < DWC3_REVISION_194A) { > + /* write zeroes to Link Change Request */ > + reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK; > + dwc3_writel(dwc->regs, DWC3_DCTL, reg); > + } > > /* poll until Link State changes to ON */ > timeout = jiffies + msecs_to_jiffies(100); > @@ -1284,9 +1312,13 @@ static void dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on) > > reg = dwc3_readl(dwc->regs, DWC3_DCTL); > if (is_on) { > - reg &= ~DWC3_DCTL_TRGTULST_MASK; > - reg |= (DWC3_DCTL_RUN_STOP > - | DWC3_DCTL_TRGTULST_RX_DET); > + if (dwc->revision <= DWC3_REVISION_187A) { > + reg &= ~DWC3_DCTL_TRGTULST_MASK; > + reg |= DWC3_DCTL_TRGTULST_RX_DET; > + } > + if (dwc->revision >= DWC3_REVISION_194A) > + reg &= ~DWC3_DCTL_KEEP_CONNECT; > + reg |= DWC3_DCTL_RUN_STOP; > } else { > reg &= ~DWC3_DCTL_RUN_STOP; > } > @@ -1409,6 +1441,7 @@ static int dwc3_gadget_stop(struct usb_gadget *g, > > return 0; > } > + > static const struct usb_gadget_ops dwc3_gadget_ops = { > .get_frame = dwc3_gadget_get_frame, > .wakeup = dwc3_gadget_wakeup, > @@ -1841,30 +1874,30 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc) > dwc->setup_packet_pending = false; > } > > -static void dwc3_gadget_usb3_phy_power(struct dwc3 *dwc, int on) > +static void dwc3_gadget_usb3_suspend_phy(struct dwc3 *dwc, int enable) > { > u32 reg; > > reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); > > - if (on) > - reg &= ~DWC3_GUSB3PIPECTL_SUSPHY; > - else > + if (enable) > reg |= DWC3_GUSB3PIPECTL_SUSPHY; > + else > + reg &= ~DWC3_GUSB3PIPECTL_SUSPHY; > > dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); > } > > -static void dwc3_gadget_usb2_phy_power(struct dwc3 *dwc, int on) > +static void dwc3_gadget_usb2_suspend_phy(struct dwc3 *dwc, int enable) > { > u32 reg; > > reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); > > - if (on) > - reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; > - else > + if (enable) > reg |= DWC3_GUSB2PHYCFG_SUSPHY; > + else > + reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; > > dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); > } > @@ -1909,9 +1942,12 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) > /* after reset -> Default State */ > dwc->dev_state = DWC3_DEFAULT_STATE; > > - /* Enable PHYs */ > - dwc3_gadget_usb2_phy_power(dwc, true); > - dwc3_gadget_usb3_phy_power(dwc, true); > + /* Recent versions support automatic phy suspend and don't need this */ > + if (dwc->revision < DWC3_REVISION_194A) { > + /* Enable PHYs */ > + dwc3_gadget_usb2_suspend_phy(dwc, false); > + dwc3_gadget_usb3_suspend_phy(dwc, false); > + } > > if (dwc->gadget.speed != USB_SPEED_UNKNOWN) > dwc3_disconnect_gadget(dwc); > @@ -1956,16 +1992,16 @@ static void dwc3_update_ram_clk_sel(struct dwc3 *dwc, u32 speed) > dwc3_writel(dwc->regs, DWC3_GCTL, reg); > } > > -static void dwc3_gadget_disable_phy(struct dwc3 *dwc, u8 speed) > +static void dwc3_gadget_suspend_phy(struct dwc3 *dwc, u8 speed) > { > switch (speed) { > case USB_SPEED_SUPER: > - dwc3_gadget_usb2_phy_power(dwc, false); > + dwc3_gadget_usb2_suspend_phy(dwc, true); > break; > case USB_SPEED_HIGH: > case USB_SPEED_FULL: > case USB_SPEED_LOW: > - dwc3_gadget_usb3_phy_power(dwc, false); > + dwc3_gadget_usb3_suspend_phy(dwc, true); > break; > } > } > @@ -2028,8 +2064,11 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) > break; > } > > - /* Disable unneded PHY */ > - dwc3_gadget_disable_phy(dwc, dwc->gadget.speed); > + /* Recent versions support automatic phy suspend and don't need this */ > + if (dwc->revision < DWC3_REVISION_194A) { > + /* Disable unneeded PHY */ > + dwc3_gadget_suspend_phy(dwc, dwc->gadget.speed); > + } > > dep = dwc->eps[0]; > ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL); > @@ -2327,6 +2366,24 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc) > DWC3_DEVTEN_DISCONNEVTEN); > dwc3_writel(dwc->regs, DWC3_DEVTEN, reg); > > + /* Enable USB2 LPM and automatic phy suspend only on recent versions */ > + if (dwc->revision >= DWC3_REVISION_194A) { > + reg = dwc3_readl(dwc->regs, DWC3_DCFG); > + reg |= DWC3_DCFG_LPM_CAP; > + dwc3_writel(dwc->regs, DWC3_DCFG, reg); > + > + reg = dwc3_readl(dwc->regs, DWC3_DCTL); > + reg &= ~(DWC3_DCTL_HIRD_THRES_MASK | DWC3_DCTL_L1_HIBER_EN); > + > + /* TODO: This should be configurable */ > + reg |= DWC3_DCTL_HIRD_THRES(31); > + > + dwc3_writel(dwc->regs, DWC3_DCTL, reg); > + > + dwc3_gadget_usb2_suspend_phy(dwc, true); > + dwc3_gadget_usb3_suspend_phy(dwc, true); > + } > + > ret = device_register(&dwc->gadget.dev); > if (ret) { > dev_err(dwc->dev, "failed to register gadget device\n"); > -- > 1.7.4.4 -- balbi
Attachment:
signature.asc
Description: Digital signature