usb: dwc3: ep0: add LPM handling
On device loading the driver enables LPM and the acceptance of U1 and U2 states. The [Set|Clear]Feature requests for "U1/U2" are forwarded directly to the hardware and allow / forbid the initiation of the low power links. Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Felipe Balbi <balbi@ti.com>
This commit is contained in:
parent
51249dca62
commit
e6a3b5e288
@ -194,6 +194,7 @@
|
|||||||
#define DWC3_GHWPARAMS1_EN_PWROPT_CLK 1
|
#define DWC3_GHWPARAMS1_EN_PWROPT_CLK 1
|
||||||
|
|
||||||
/* Device Configuration Register */
|
/* Device Configuration Register */
|
||||||
|
#define DWC3_DCFG_LPM_CAP (1 << 22)
|
||||||
#define DWC3_DCFG_DEVADDR(addr) ((addr) << 3)
|
#define DWC3_DCFG_DEVADDR(addr) ((addr) << 3)
|
||||||
#define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f)
|
#define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f)
|
||||||
|
|
||||||
|
@ -261,6 +261,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc,
|
|||||||
{
|
{
|
||||||
struct dwc3_ep *dep;
|
struct dwc3_ep *dep;
|
||||||
u32 recip;
|
u32 recip;
|
||||||
|
u32 reg;
|
||||||
u16 usb_status = 0;
|
u16 usb_status = 0;
|
||||||
__le16 *response_pkt;
|
__le16 *response_pkt;
|
||||||
|
|
||||||
@ -268,10 +269,18 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc,
|
|||||||
switch (recip) {
|
switch (recip) {
|
||||||
case USB_RECIP_DEVICE:
|
case USB_RECIP_DEVICE:
|
||||||
/*
|
/*
|
||||||
* We are self-powered. U1/U2/LTM will be set later
|
* LTM will be set once we know how to set this in HW.
|
||||||
* once we handle this states. RemoteWakeup is 0 on SS
|
|
||||||
*/
|
*/
|
||||||
usb_status |= dwc->is_selfpowered << USB_DEVICE_SELF_POWERED;
|
usb_status |= dwc->is_selfpowered << USB_DEVICE_SELF_POWERED;
|
||||||
|
|
||||||
|
if (dwc->speed == DWC3_DSTS_SUPERSPEED) {
|
||||||
|
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
|
||||||
|
if (reg & DWC3_DCTL_INITU1ENA)
|
||||||
|
usb_status |= 1 << USB_DEV_STAT_U1_ENABLED;
|
||||||
|
if (reg & DWC3_DCTL_INITU2ENA)
|
||||||
|
usb_status |= 1 << USB_DEV_STAT_U2_ENABLED;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case USB_RECIP_INTERFACE:
|
case USB_RECIP_INTERFACE:
|
||||||
@ -312,6 +321,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
|
|||||||
u32 recip;
|
u32 recip;
|
||||||
u32 wValue;
|
u32 wValue;
|
||||||
u32 wIndex;
|
u32 wIndex;
|
||||||
|
u32 reg;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
wValue = le16_to_cpu(ctrl->wValue);
|
wValue = le16_to_cpu(ctrl->wValue);
|
||||||
@ -320,29 +330,43 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
|
|||||||
switch (recip) {
|
switch (recip) {
|
||||||
case USB_RECIP_DEVICE:
|
case USB_RECIP_DEVICE:
|
||||||
|
|
||||||
|
switch (wValue) {
|
||||||
|
case USB_DEVICE_REMOTE_WAKEUP:
|
||||||
|
break;
|
||||||
/*
|
/*
|
||||||
* 9.4.1 says only only for SS, in AddressState only for
|
* 9.4.1 says only only for SS, in AddressState only for
|
||||||
* default control pipe
|
* default control pipe
|
||||||
*/
|
*/
|
||||||
switch (wValue) {
|
|
||||||
case USB_DEVICE_U1_ENABLE:
|
case USB_DEVICE_U1_ENABLE:
|
||||||
case USB_DEVICE_U2_ENABLE:
|
|
||||||
case USB_DEVICE_LTM_ENABLE:
|
|
||||||
if (dwc->dev_state != DWC3_CONFIGURED_STATE)
|
if (dwc->dev_state != DWC3_CONFIGURED_STATE)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (dwc->speed != DWC3_DSTS_SUPERSPEED)
|
if (dwc->speed != DWC3_DSTS_SUPERSPEED)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
|
||||||
|
|
||||||
/* XXX add U[12] & LTM */
|
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
|
||||||
switch (wValue) {
|
if (set)
|
||||||
case USB_DEVICE_REMOTE_WAKEUP:
|
reg |= DWC3_DCTL_INITU1ENA;
|
||||||
break;
|
else
|
||||||
case USB_DEVICE_U1_ENABLE:
|
reg &= ~DWC3_DCTL_INITU1ENA;
|
||||||
|
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case USB_DEVICE_U2_ENABLE:
|
case USB_DEVICE_U2_ENABLE:
|
||||||
|
if (dwc->dev_state != DWC3_CONFIGURED_STATE)
|
||||||
|
return -EINVAL;
|
||||||
|
if (dwc->speed != DWC3_DSTS_SUPERSPEED)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
|
||||||
|
if (set)
|
||||||
|
reg |= DWC3_DCTL_INITU2ENA;
|
||||||
|
else
|
||||||
|
reg &= ~DWC3_DCTL_INITU2ENA;
|
||||||
|
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case USB_DEVICE_LTM_ENABLE:
|
case USB_DEVICE_LTM_ENABLE:
|
||||||
|
return -EINVAL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case USB_DEVICE_TEST_MODE:
|
case USB_DEVICE_TEST_MODE:
|
||||||
|
@ -1933,6 +1933,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
|
|||||||
|
|
||||||
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
|
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
|
||||||
reg &= ~DWC3_DCTL_TSTCTRL_MASK;
|
reg &= ~DWC3_DCTL_TSTCTRL_MASK;
|
||||||
|
reg &= ~(DWC3_DCTL_INITU1ENA | DWC3_DCTL_INITU2ENA);
|
||||||
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
|
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
|
||||||
dwc->test_mode = false;
|
dwc->test_mode = false;
|
||||||
|
|
||||||
@ -2330,6 +2331,14 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)
|
|||||||
goto err5;
|
goto err5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA;
|
||||||
|
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
|
||||||
|
|
||||||
/* Enable all but Start and End of Frame IRQs */
|
/* Enable all but Start and End of Frame IRQs */
|
||||||
reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN |
|
reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN |
|
||||||
DWC3_DEVTEN_EVNTOVERFLOWEN |
|
DWC3_DEVTEN_EVNTOVERFLOWEN |
|
||||||
|
Loading…
Reference in New Issue
Block a user