aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDouglas Anderson <dianders@chromium.org>2019-04-17 20:13:52 -0400
committerFelipe Balbi <felipe.balbi@linux.intel.com>2019-05-03 02:13:47 -0400
commit6f6d70597c15b2a406afa541517e6ad35f56a8a3 (patch)
treeb0cfa4aa1a03b80fec24a905e108eb5ec3c3a2ba
parentc99993376f72ca3dcc989813512607c6435cbed8 (diff)
usb: dwc2: bus suspend/resume for hosts with DWC2_POWER_DOWN_PARAM_NONE
This is an attempt to rehash commit 0cf884e819e0 ("usb: dwc2: add bus suspend/resume for dwc2") on ToT. That commit was reverted in commit b0bb9bb6ce01 ("Revert "usb: dwc2: add bus suspend/resume for dwc2"") because apparently it broke the Altera SOCFPGA. With all the changes that have happened to dwc2 in the meantime, it's possible that the Altera SOCFPGA will just magically work with this change now. ...and it would be good to get bus suspend/resume implemented. This change is a forward port of one that's been living in the Chrome OS 3.14 kernel tree. Signed-off-by: Douglas Anderson <dianders@chromium.org> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
-rw-r--r--drivers/usb/dwc2/hcd.c84
1 files changed, 53 insertions, 31 deletions
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 3f087962f498..8667ddf3ca74 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -4471,6 +4471,7 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd)
4471 unsigned long flags; 4471 unsigned long flags;
4472 int ret = 0; 4472 int ret = 0;
4473 u32 hprt0; 4473 u32 hprt0;
4474 u32 pcgctl;
4474 4475
4475 spin_lock_irqsave(&hsotg->lock, flags); 4476 spin_lock_irqsave(&hsotg->lock, flags);
4476 4477
@@ -4486,7 +4487,7 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd)
4486 if (hsotg->op_state == OTG_STATE_B_PERIPHERAL) 4487 if (hsotg->op_state == OTG_STATE_B_PERIPHERAL)
4487 goto unlock; 4488 goto unlock;
4488 4489
4489 if (hsotg->params.power_down != DWC2_POWER_DOWN_PARAM_PARTIAL) 4490 if (hsotg->params.power_down > DWC2_POWER_DOWN_PARAM_PARTIAL)
4490 goto skip_power_saving; 4491 goto skip_power_saving;
4491 4492
4492 /* 4493 /*
@@ -4495,21 +4496,35 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd)
4495 */ 4496 */
4496 if (!hsotg->bus_suspended) { 4497 if (!hsotg->bus_suspended) {
4497 hprt0 = dwc2_read_hprt0(hsotg); 4498 hprt0 = dwc2_read_hprt0(hsotg);
4498 hprt0 |= HPRT0_SUSP; 4499 if (hprt0 & HPRT0_CONNSTS) {
4499 hprt0 &= ~HPRT0_PWR; 4500 hprt0 |= HPRT0_SUSP;
4500 dwc2_writel(hsotg, hprt0, HPRT0); 4501 if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_PARTIAL)
4501 spin_unlock_irqrestore(&hsotg->lock, flags); 4502 hprt0 &= ~HPRT0_PWR;
4502 dwc2_vbus_supply_exit(hsotg); 4503 dwc2_writel(hsotg, hprt0, HPRT0);
4503 spin_lock_irqsave(&hsotg->lock, flags); 4504 }
4505 if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_PARTIAL) {
4506 spin_unlock_irqrestore(&hsotg->lock, flags);
4507 dwc2_vbus_supply_exit(hsotg);
4508 spin_lock_irqsave(&hsotg->lock, flags);
4509 } else {
4510 pcgctl = readl(hsotg->regs + PCGCTL);
4511 pcgctl |= PCGCTL_STOPPCLK;
4512 writel(pcgctl, hsotg->regs + PCGCTL);
4513 }
4504 } 4514 }
4505 4515
4506 /* Enter partial_power_down */ 4516 if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_PARTIAL) {
4507 ret = dwc2_enter_partial_power_down(hsotg); 4517 /* Enter partial_power_down */
4508 if (ret) { 4518 ret = dwc2_enter_partial_power_down(hsotg);
4509 if (ret != -ENOTSUPP) 4519 if (ret) {
4510 dev_err(hsotg->dev, 4520 if (ret != -ENOTSUPP)
4511 "enter partial_power_down failed\n"); 4521 dev_err(hsotg->dev,
4512 goto skip_power_saving; 4522 "enter partial_power_down failed\n");
4523 goto skip_power_saving;
4524 }
4525
4526 /* After entering partial_power_down, hardware is no more accessible */
4527 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
4513 } 4528 }
4514 4529
4515 /* Ask phy to be suspended */ 4530 /* Ask phy to be suspended */
@@ -4519,9 +4534,6 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd)
4519 spin_lock_irqsave(&hsotg->lock, flags); 4534 spin_lock_irqsave(&hsotg->lock, flags);
4520 } 4535 }
4521 4536
4522 /* After entering partial_power_down, hardware is no more accessible */
4523 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
4524
4525skip_power_saving: 4537skip_power_saving:
4526 hsotg->lx_state = DWC2_L2; 4538 hsotg->lx_state = DWC2_L2;
4527unlock: 4539unlock:
@@ -4534,6 +4546,7 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd)
4534{ 4546{
4535 struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); 4547 struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
4536 unsigned long flags; 4548 unsigned long flags;
4549 u32 pcgctl;
4537 int ret = 0; 4550 int ret = 0;
4538 4551
4539 spin_lock_irqsave(&hsotg->lock, flags); 4552 spin_lock_irqsave(&hsotg->lock, flags);
@@ -4544,18 +4557,12 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd)
4544 if (hsotg->lx_state != DWC2_L2) 4557 if (hsotg->lx_state != DWC2_L2)
4545 goto unlock; 4558 goto unlock;
4546 4559
4547 if (hsotg->params.power_down != DWC2_POWER_DOWN_PARAM_PARTIAL) { 4560 if (hsotg->params.power_down > DWC2_POWER_DOWN_PARAM_PARTIAL) {
4548 hsotg->lx_state = DWC2_L0; 4561 hsotg->lx_state = DWC2_L0;
4549 goto unlock; 4562 goto unlock;
4550 } 4563 }
4551 4564
4552 /* 4565 /*
4553 * Set HW accessible bit before powering on the controller
4554 * since an interrupt may rise.
4555 */
4556 set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
4557
4558 /*
4559 * Enable power if not already done. 4566 * Enable power if not already done.
4560 * This must not be spinlocked since duration 4567 * This must not be spinlocked since duration
4561 * of this call is unknown. 4568 * of this call is unknown.
@@ -4566,10 +4573,23 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd)
4566 spin_lock_irqsave(&hsotg->lock, flags); 4573 spin_lock_irqsave(&hsotg->lock, flags);
4567 } 4574 }
4568 4575
4569 /* Exit partial_power_down */ 4576 if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_PARTIAL) {
4570 ret = dwc2_exit_partial_power_down(hsotg, true); 4577 /*
4571 if (ret && (ret != -ENOTSUPP)) 4578 * Set HW accessible bit before powering on the controller
4572 dev_err(hsotg->dev, "exit partial_power_down failed\n"); 4579 * since an interrupt may rise.
4580 */
4581 set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
4582
4583
4584 /* Exit partial_power_down */
4585 ret = dwc2_exit_partial_power_down(hsotg, true);
4586 if (ret && (ret != -ENOTSUPP))
4587 dev_err(hsotg->dev, "exit partial_power_down failed\n");
4588 } else {
4589 pcgctl = readl(hsotg->regs + PCGCTL);
4590 pcgctl &= ~PCGCTL_STOPPCLK;
4591 writel(pcgctl, hsotg->regs + PCGCTL);
4592 }
4573 4593
4574 hsotg->lx_state = DWC2_L0; 4594 hsotg->lx_state = DWC2_L0;
4575 4595
@@ -4581,10 +4601,12 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd)
4581 spin_unlock_irqrestore(&hsotg->lock, flags); 4601 spin_unlock_irqrestore(&hsotg->lock, flags);
4582 dwc2_port_resume(hsotg); 4602 dwc2_port_resume(hsotg);
4583 } else { 4603 } else {
4584 dwc2_vbus_supply_init(hsotg); 4604 if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_PARTIAL) {
4605 dwc2_vbus_supply_init(hsotg);
4585 4606
4586 /* Wait for controller to correctly update D+/D- level */ 4607 /* Wait for controller to correctly update D+/D- level */
4587 usleep_range(3000, 5000); 4608 usleep_range(3000, 5000);
4609 }
4588 4610
4589 /* 4611 /*
4590 * Clear Port Enable and Port Status changes. 4612 * Clear Port Enable and Port Status changes.