usb: dwc3: Allow controller to enter LPM in bus suspend
Add a DT property that decides whether to allow controller low power mode upon bus suspend, which will be invoked by the OTG state machine. It is also required to take the core out of LPM in case ep_queue is called by the upper layers. In this case, remote wakeup sequence will be initiated once the core is out of LPM. [jackp@codeaurora.org: Squashed with dwc3 changes from "usb: dwc3: Add new OTG state OTG_STATE_B_SUSPENDED"] Signed-off-by: Jack Pham <jackp@codeaurora.org>
This commit is contained in:
parent
1e50e387dd
commit
5fb67a4aa5
4 changed files with 59 additions and 5 deletions
|
@ -51,6 +51,8 @@ Optional properties:
|
|||
- snps,usb3-u1u2-disable: If present, disable u1u2 low power modes for DWC3 core
|
||||
controller in SS mode.
|
||||
- snps,disable-clk-gating: If present, disable controller's internal clock gating. Default it is enabled.
|
||||
- snps,bus-suspend-enable: If present then controller supports low power mode
|
||||
during bus suspend.
|
||||
|
||||
This is usually a subnode to DWC3 glue to which it is connected.
|
||||
|
||||
|
|
|
@ -1034,6 +1034,13 @@ static int dwc3_probe(struct platform_device *pdev)
|
|||
"snps,usb3-u1u2-disable");
|
||||
dwc->disable_clk_gating = device_property_read_bool(dev,
|
||||
"snps,disable-clk-gating");
|
||||
dwc->enable_bus_suspend = device_property_read_bool(dev,
|
||||
"snps,bus-suspend-enable");
|
||||
if (dwc->enable_bus_suspend) {
|
||||
pm_runtime_set_autosuspend_delay(dev, 500);
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
}
|
||||
|
||||
if (pdata) {
|
||||
dwc->maximum_speed = pdata->maximum_speed;
|
||||
dwc->has_lpm_erratum = pdata->has_lpm_erratum;
|
||||
|
|
|
@ -713,6 +713,8 @@ struct dwc3_scratchpad_array {
|
|||
#define DWC3_CONTROLLER_POST_RESET_EVENT 2
|
||||
#define DWC3_CORE_PM_SUSPEND_EVENT 3
|
||||
#define DWC3_CORE_PM_RESUME_EVENT 4
|
||||
#define DWC3_CONTROLLER_CONNDONE_EVENT 8
|
||||
#define DWC3_CONTROLLER_NOTIFY_OTG_EVENT 9
|
||||
|
||||
#define MAX_INTR_STATS 10
|
||||
/**
|
||||
|
@ -965,11 +967,13 @@ struct dwc3 {
|
|||
unsigned usb3_u1u2_disable:1;
|
||||
/* Indicate if need to disable controller internal clkgating */
|
||||
unsigned disable_clk_gating:1;
|
||||
unsigned enable_bus_suspend:1;
|
||||
|
||||
struct dwc3_gadget_events dbg_gadget_events;
|
||||
|
||||
atomic_t in_lpm;
|
||||
int tx_fifo_size;
|
||||
bool b_suspend;
|
||||
|
||||
/* IRQ timing statistics */
|
||||
int irq;
|
||||
|
|
|
@ -1299,7 +1299,6 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
|
|||
struct dwc3 *dwc = dep->dwc;
|
||||
|
||||
unsigned long flags;
|
||||
|
||||
int ret;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
|
@ -1346,6 +1345,11 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
|
|||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
if (atomic_read(&dwc->in_lpm)) {
|
||||
dev_err(dwc->dev, "Unable to dequeue while in LPM\n");
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
trace_dwc3_ep_dequeue(req);
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
|
@ -1522,6 +1526,8 @@ static void dwc3_gadget_wakeup_work(struct work_struct *w)
|
|||
if (atomic_read(&dwc->in_lpm)) {
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
pm_runtime_get_sync(dwc->dev);
|
||||
dbg_event(0xFF, "Gdgwake gsyn",
|
||||
atomic_read(&dwc->dev->power.usage_count));
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
}
|
||||
|
||||
|
@ -1748,10 +1754,28 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
|
|||
|
||||
is_on = !!is_on;
|
||||
|
||||
pm_runtime_get_sync(dwc->dev);
|
||||
dbg_event(0xFF, "Pullup gsync",
|
||||
atomic_read(&dwc->dev->power.usage_count));
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
|
||||
/*
|
||||
* If we are here after bus suspend notify otg state machine to
|
||||
* increment pm usage count of dwc to prevent pm_runtime_suspend
|
||||
* during enumeration.
|
||||
*/
|
||||
dev_dbg(dwc->dev, "Notify OTG from %s\n", __func__);
|
||||
dwc->b_suspend = false;
|
||||
dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT);
|
||||
|
||||
ret = dwc3_gadget_run_stop(dwc, is_on, false);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
pm_runtime_put_noidle(dwc->dev);
|
||||
dbg_event(0xFF, "Pullup put",
|
||||
atomic_read(&dwc->dev->power.usage_count));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -2490,6 +2514,10 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
|
|||
{
|
||||
int reg;
|
||||
|
||||
dev_dbg(dwc->dev, "Notify OTG from %s\n", __func__);
|
||||
dwc->b_suspend = false;
|
||||
dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT);
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
|
||||
reg &= ~DWC3_DCTL_INITU1ENA;
|
||||
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
|
||||
|
@ -2541,6 +2569,10 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
|
|||
dwc3_gadget_disconnect_interrupt(dwc);
|
||||
}
|
||||
|
||||
dev_dbg(dwc->dev, "Notify OTG from %s\n", __func__);
|
||||
dwc->b_suspend = false;
|
||||
dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT);
|
||||
|
||||
dwc3_usb3_phy_suspend(dwc, false);
|
||||
|
||||
dwc3_reset_gadget(dwc);
|
||||
|
@ -2697,6 +2729,8 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
|
|||
return;
|
||||
}
|
||||
|
||||
dwc3_notify_event(dwc, DWC3_CONTROLLER_CONNDONE_EVENT);
|
||||
|
||||
/*
|
||||
* Configure PHY via GUSB3PIPECTLn if required.
|
||||
*
|
||||
|
@ -2708,10 +2742,12 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
|
|||
|
||||
static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc)
|
||||
{
|
||||
/*
|
||||
* TODO take core out of low power mode when that's
|
||||
* implemented.
|
||||
*/
|
||||
dbg_event(0xFF, "WAKEUP", 0);
|
||||
|
||||
dev_dbg(dwc->dev, "Notify OTG from %s\n", __func__);
|
||||
dwc->b_suspend = false;
|
||||
dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT);
|
||||
|
||||
dwc3_resume_gadget(dwc);
|
||||
}
|
||||
|
||||
|
@ -2862,6 +2898,10 @@ static void dwc3_gadget_suspend_interrupt(struct dwc3 *dwc,
|
|||
}
|
||||
|
||||
dwc3_suspend_gadget(dwc);
|
||||
|
||||
dev_dbg(dwc->dev, "Notify OTG from %s\n", __func__);
|
||||
dwc->b_suspend = true;
|
||||
dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT);
|
||||
}
|
||||
|
||||
dwc->link_state = next;
|
||||
|
@ -2931,6 +2971,7 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc,
|
|||
dwc3_trace(trace_dwc3_gadget, "U3/L1-L2 Suspend Event");
|
||||
dbg_event(0xFF, "GAD SUS", 0);
|
||||
dwc->dbg_gadget_events.suspend++;
|
||||
|
||||
dwc3_gadget_suspend_interrupt(dwc, event->event_info);
|
||||
}
|
||||
break;
|
||||
|
|
Loading…
Add table
Reference in a new issue