aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/dwc2/hcd.c
diff options
context:
space:
mode:
authorFabrice Gasnier <fabrice.gasnier@st.com>2018-09-05 07:40:05 -0400
committerFelipe Balbi <felipe.balbi@linux.intel.com>2018-10-02 03:37:40 -0400
commitcd7cd0e6cedfda8da6668a4af6748f96bbb6fed4 (patch)
tree7913ab4b03936f6dc479426adf64a33ddb26fd50 /drivers/usb/dwc2/hcd.c
parent5aa678c7fd5371769efde30763fb43a43a118cd0 (diff)
usb: dwc2: fix unbalanced use of external vbus-supply
When using external vbus supply regulator, it should be enabled synchronously with PWR bit in HPRT register. This also fixes unbalanced use of this optional regulator (This can be reproduced easily when unbinding the driver). Fixes: 531ef5ebea96 ("usb: dwc2: add support for host mode external vbus supply") Tested-by: Artur Petrosyan <arturp@synopsys.com> Acked-by: Minas Harutyunyan <hminas@synopsys.com> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com> Signed-off-by: Amelie Delaunay <amelie.delaunay@st.com> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
Diffstat (limited to 'drivers/usb/dwc2/hcd.c')
-rw-r--r--drivers/usb/dwc2/hcd.c33
1 files changed, 26 insertions, 7 deletions
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 103a0521466b..dd82fa516f3f 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -3555,6 +3555,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
3555 u32 port_status; 3555 u32 port_status;
3556 u32 speed; 3556 u32 speed;
3557 u32 pcgctl; 3557 u32 pcgctl;
3558 u32 pwr;
3558 3559
3559 switch (typereq) { 3560 switch (typereq) {
3560 case ClearHubFeature: 3561 case ClearHubFeature:
@@ -3603,8 +3604,11 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
3603 dev_dbg(hsotg->dev, 3604 dev_dbg(hsotg->dev,
3604 "ClearPortFeature USB_PORT_FEAT_POWER\n"); 3605 "ClearPortFeature USB_PORT_FEAT_POWER\n");
3605 hprt0 = dwc2_read_hprt0(hsotg); 3606 hprt0 = dwc2_read_hprt0(hsotg);
3607 pwr = hprt0 & HPRT0_PWR;
3606 hprt0 &= ~HPRT0_PWR; 3608 hprt0 &= ~HPRT0_PWR;
3607 dwc2_writel(hsotg, hprt0, HPRT0); 3609 dwc2_writel(hsotg, hprt0, HPRT0);
3610 if (pwr)
3611 dwc2_vbus_supply_exit(hsotg);
3608 break; 3612 break;
3609 3613
3610 case USB_PORT_FEAT_INDICATOR: 3614 case USB_PORT_FEAT_INDICATOR:
@@ -3814,8 +3818,11 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
3814 dev_dbg(hsotg->dev, 3818 dev_dbg(hsotg->dev,
3815 "SetPortFeature - USB_PORT_FEAT_POWER\n"); 3819 "SetPortFeature - USB_PORT_FEAT_POWER\n");
3816 hprt0 = dwc2_read_hprt0(hsotg); 3820 hprt0 = dwc2_read_hprt0(hsotg);
3821 pwr = hprt0 & HPRT0_PWR;
3817 hprt0 |= HPRT0_PWR; 3822 hprt0 |= HPRT0_PWR;
3818 dwc2_writel(hsotg, hprt0, HPRT0); 3823 dwc2_writel(hsotg, hprt0, HPRT0);
3824 if (!pwr)
3825 dwc2_vbus_supply_init(hsotg);
3819 break; 3826 break;
3820 3827
3821 case USB_PORT_FEAT_RESET: 3828 case USB_PORT_FEAT_RESET:
@@ -3832,6 +3839,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
3832 dwc2_writel(hsotg, 0, PCGCTL); 3839 dwc2_writel(hsotg, 0, PCGCTL);
3833 3840
3834 hprt0 = dwc2_read_hprt0(hsotg); 3841 hprt0 = dwc2_read_hprt0(hsotg);
3842 pwr = hprt0 & HPRT0_PWR;
3835 /* Clear suspend bit if resetting from suspend state */ 3843 /* Clear suspend bit if resetting from suspend state */
3836 hprt0 &= ~HPRT0_SUSP; 3844 hprt0 &= ~HPRT0_SUSP;
3837 3845
@@ -3845,6 +3853,8 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
3845 dev_dbg(hsotg->dev, 3853 dev_dbg(hsotg->dev,
3846 "In host mode, hprt0=%08x\n", hprt0); 3854 "In host mode, hprt0=%08x\n", hprt0);
3847 dwc2_writel(hsotg, hprt0, HPRT0); 3855 dwc2_writel(hsotg, hprt0, HPRT0);
3856 if (!pwr)
3857 dwc2_vbus_supply_init(hsotg);
3848 } 3858 }
3849 3859
3850 /* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */ 3860 /* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */
@@ -4384,6 +4394,7 @@ static int _dwc2_hcd_start(struct usb_hcd *hcd)
4384 struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); 4394 struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
4385 struct usb_bus *bus = hcd_to_bus(hcd); 4395 struct usb_bus *bus = hcd_to_bus(hcd);
4386 unsigned long flags; 4396 unsigned long flags;
4397 u32 hprt0;
4387 int ret; 4398 int ret;
4388 4399
4389 dev_dbg(hsotg->dev, "DWC OTG HCD START\n"); 4400 dev_dbg(hsotg->dev, "DWC OTG HCD START\n");
@@ -4400,12 +4411,16 @@ static int _dwc2_hcd_start(struct usb_hcd *hcd)
4400 4411
4401 dwc2_hcd_reinit(hsotg); 4412 dwc2_hcd_reinit(hsotg);
4402 4413
4403 /* enable external vbus supply before resuming root hub */ 4414 hprt0 = dwc2_read_hprt0(hsotg);
4404 spin_unlock_irqrestore(&hsotg->lock, flags); 4415 /* Has vbus power been turned on in dwc2_core_host_init ? */
4405 ret = dwc2_vbus_supply_init(hsotg); 4416 if (hprt0 & HPRT0_PWR) {
4406 if (ret) 4417 /* Enable external vbus supply before resuming root hub */
4407 return ret; 4418 spin_unlock_irqrestore(&hsotg->lock, flags);
4408 spin_lock_irqsave(&hsotg->lock, flags); 4419 ret = dwc2_vbus_supply_init(hsotg);
4420 if (ret)
4421 return ret;
4422 spin_lock_irqsave(&hsotg->lock, flags);
4423 }
4409 4424
4410 /* Initialize and connect root hub if one is not already attached */ 4425 /* Initialize and connect root hub if one is not already attached */
4411 if (bus->root_hub) { 4426 if (bus->root_hub) {
@@ -4427,6 +4442,7 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd)
4427{ 4442{
4428 struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); 4443 struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
4429 unsigned long flags; 4444 unsigned long flags;
4445 u32 hprt0;
4430 4446
4431 /* Turn off all host-specific interrupts */ 4447 /* Turn off all host-specific interrupts */
4432 dwc2_disable_host_interrupts(hsotg); 4448 dwc2_disable_host_interrupts(hsotg);
@@ -4435,6 +4451,7 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd)
4435 synchronize_irq(hcd->irq); 4451 synchronize_irq(hcd->irq);
4436 4452
4437 spin_lock_irqsave(&hsotg->lock, flags); 4453 spin_lock_irqsave(&hsotg->lock, flags);
4454 hprt0 = dwc2_read_hprt0(hsotg);
4438 /* Ensure hcd is disconnected */ 4455 /* Ensure hcd is disconnected */
4439 dwc2_hcd_disconnect(hsotg, true); 4456 dwc2_hcd_disconnect(hsotg, true);
4440 dwc2_hcd_stop(hsotg); 4457 dwc2_hcd_stop(hsotg);
@@ -4443,7 +4460,9 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd)
4443 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); 4460 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
4444 spin_unlock_irqrestore(&hsotg->lock, flags); 4461 spin_unlock_irqrestore(&hsotg->lock, flags);
4445 4462
4446 dwc2_vbus_supply_exit(hsotg); 4463 /* keep balanced supply init/exit by checking HPRT0_PWR */
4464 if (hprt0 & HPRT0_PWR)
4465 dwc2_vbus_supply_exit(hsotg);
4447 4466
4448 usleep_range(1000, 3000); 4467 usleep_range(1000, 3000);
4449} 4468}